我在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或更短的列表。
答案 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