我有以下过程,该过程采用字符串列表并生成它的组合:
val a = List(("a","a"),("a","b"),("a","c"),("b","a"),("b","b"),("b","c"),("c","a"),("c","b"),("c","c"));
并且我正在尝试生成3的组合列表(因为3是集合中不同字母的数量),其中每个成员离开仅映射到右侧的1个不同成员,反之亦然。
例如,我期望的输出类似于:
List(("a","a"),("b","b"),("c","c"))
但它不能像:
List (("a","a"),("b","a"),("a","c"))
所以我写了以下内容:
val res = a
.combinations(3)
.toList
.filter(x =>
x.map(y => y._1).distinct.size == 3
&& x.map(y => y._2).distinct.size == 3
)
生成正确的答案集:
List((a,a), (b,b), (c,c))
List((a,a), (b,c), (c,b))
List((a,b), (b,a), (c,c))
List((a,b), (b,c), (c,a))
List((a,c), (b,a), (c,b))
List((a,c), (b,b), (c,a))
但是当我增加a的大小以及组合的数量时,我正在达到GC开销。我想知道是否有办法在不使用组合功能的情况下以更高效的方式做我想做的事情?我正在使用Spark,所以我也可以使用任何Spark函数 - 虽然我认为没有。
答案 0 :(得分:2)
嗯,确实Spark没有combinations
功能,但您可以使用cartesian
的连续调用来模仿它。它在性能方面可能效率不高,但它应该可以防止您遇到的内存问题并解决collect
(具有自己的性能成本)的需求:
val values: RDD[(String, String)] = sc.parallelize(a)
val combinationSize = 3 // can be increased
// mimic Scala's "combination" by repeating RDD.cartesian N times:
val combinations: RDD[Set[(String, String)]] = (1 until combinationSize)
.foldLeft(values.map(Set(_))) {
case (rdd, index) => rdd.cartesian(values).map { case (set, t2) => set + t2 }.distinct
}
// removing "illegal" combinations - since we're using sets we don't need to call "distinct":
val res = combinations
.filter(_.map(_._1).size == combinationSize)
.filter(_.map(_._2).size == combinationSize)