Scala分区为两个以上的列表

时间:2014-10-31 12:54:45

标签: list scala

我在Scala中有一个列表,我正在尝试根据涉及列表中多个元素的谓词划分为多个列表。例如,如果我有

a: List[String] = List("a", "ab", "b", "abc", "c")

我希望获得b: List[List[String]]这是List[String]的列表,以便内部List[String] == 3的长度总和。即List(List("a", "b", "c"), List("abc"), List("ab", "a"), ...)

[编辑]需要花费合理的时间来查看长度为50或更短的列表。

3 个答案:

答案 0 :(得分:1)

构建所有可能的子列表并过滤:

def filter[A](list: List[A])(predicate: (List[A] => Boolean)): List[List[A]] = {
  (for {i <- 1 to list.length
        subList <- list.combinations(i)
        if predicate(subList)
  } yield subList).toList
}

val a = List("a", "ab", "b", "abc", "c")

val result = filter(a)(_.foldLeft(0)(_ + _.length) == 3)

答案 1 :(得分:1)

对于任何任意谓词O(2^n * O(p)),无法构建比p便宜的高效算法。这是因为必须评估每个子集。你将永远无法实现适用于n == 50的东西。

答案 2 :(得分:1)

我认为谢尔盖在这里走得很好,但我们可以稍微优化他的代码。首先,我们可以注意到,如果字符串长度的总和是N,那么我们确定不需要检查由超过N个字符串组成的组合,因为最短的字符串至少是一个字符长。此外,我们可以在没有 for synctatic糖的情况下离开并使用 sum 方法而不是更通用的方法(因此,可能不那么快) foldLeft

为了清楚起见,让我们首先定义一个小辅助函数,它将计算字符串长度的总和:

def sumOfStr(list: List[String]) = list.map(_.length).sum

现在的主要方法是:

def split(list: List[String], sum: Int) = 
  (1 to sum).map(list.combinations(_).filter(sumOfStr(_) == sum)).flatten.toList

编辑:在我们的权力合并之后,我们会给你一个效率仍然非常低效的但是嘿 - 这是我们能够做到最好的合理时间版本:

def sumOfStr(lst: List[String]) = {
  var sum = 0
  lst.foreach{ sum += _.length }
  sum  
}

def split(lst: List[String], sum: Int) = 
  (1 to sum).par
  .map(lst.combinations(_).filter(sumOfStr(_) == sum))
  .flatten.toList