我有以下一组集。提前不知道多久。在Scala中将Set [Set [String]]展开为笛卡尔积
val sets = Set(Set("a","b","c"), Set("1","2"), Set("S","T"))
我想将其扩展成笛卡尔乘积:
Set("a&1&S", "a&1&T", "a&2&S", ..., "c&2&T")
你会如何做呢?
我有以下一组集。提前不知道多久。在Scala中将Set [Set [String]]展开为笛卡尔积
val sets = Set(Set("a","b","c"), Set("1","2"), Set("S","T"))
我想将其扩展成笛卡尔乘积:
Set("a&1&S", "a&1&T", "a&2&S", ..., "c&2&T")
你会如何做呢?
我想我想出了如何做到这一点。
def combine(acc:Set[String], set:Set[String]) = for (a <- acc; s <- set) yield {
a + "&" + s
}
val expanded = sets.reduceLeft(combine)
expanded: scala.collection.immutable.Set[java.lang.String] = Set(b&2&T, a&1&S,
a&1&T, b&1&S, b&1&T, c&1&T, a&2&T, c&1&S, c&2&T, a&2&S, c&2&S, b&2&S)
不错的问题。这里有一种方法:
scala> val seqs = Seq(Seq("a","b","c"), Seq("1","2"), Seq("S","T"))
seqs: Seq[Seq[java.lang.String]] = List(List(a, b, c), List(1, 2), List(S, T))
scala> val seqs2 = seqs.map(_.map(Seq(_)))
seqs2: Seq[Seq[Seq[java.lang.String]]] = List(List(List(a), List(b), List(c)), List(List(1), List(2)), List(List(S), List(T)))
scala> val combined = seqs2.reduceLeft((xs, ys) => for {x <- xs; y <- ys} yield x ++ y)
combined: Seq[Seq[java.lang.String]] = List(List(a, 1, S), List(a, 1, T), List(a, 2, S), List(a, 2, T), List(b, 1, S), List(b, 1, T), List(b, 2, S), List(b, 2, T), List(c, 1, S), List(c, 1, T), List(c, 2, S), List(c, 2, T))
scala> combined.map(_.mkString("&"))
res11: Seq[String] = List(a&1&S, a&1&T, a&2&S, a&2&T, b&1&S, b&1&T, b&2&S, b&2&T, c&1&S, c&1&T, c&2&S, c&2&T)
谢谢。我第一次尝试foldLeft并最终想出我需要使用reduceLeft来代替(不断得到一个空的结果)。转换为Seq只是为了保持排序? – huynhjl 2010-05-23 16:02:39
最后的结合实际上是有帮助的,因为这些集合实际上在同一个空间中,我需要将“b&a&a”合并到“a&b”中(删除dups并排列组合)。 – huynhjl 2010-05-23 16:10:58
@huynhjl seq(开头)的使用可能是为了避免导入'scala.collection.immutable.Set',并且可能显示这可以用更一般的接口完成。 – 2010-05-23 16:23:17
的batle后,来到;),但另一个问题:
sets.reduceLeft((s0,s1)=>s0.flatMap(a=>s1.map(a+"&"+_)))
扩展在@Patrick's answer。 现在是更普遍的和懒惰:
def combine[A](f:(A, A) => A)(xs:Iterable[Iterable[A]]) =
xs.reduceLeft { (x, y) => x.view.flatMap {a => y.map(f(a, _)) } }
有它偷懒可以让你节省空间,因为你不存储在扩展集的成倍许多项目;相反,您可以即时生成它们。但是,如果你真的想要全套,你仍然可以得到它像这样:
val expanded = combine{(x:String, y:String) => x + "&" + y}(sets).toSet
下面是一个更通用的解决方案,可以在采用笛卡尔产品之前对地图进行应用:http://stackoverflow.com/a/4515050/244526 – dsg 2011-12-19 06:15:25
扩展在dsg's answer,可以更清晰地写出来(我认为)这样,如果你不介意的咖喱功能:
def combine[A](f: A => A => A)(xs:Iterable[Iterable[A]]) =
xs reduceLeft { (x, y) => x.view flatMap { y map f(_) } }
另一种替代方法(稍长,但更可读):
def combine[A](f: (A, A) => A)(xs:Iterable[Iterable[A]]) =
xs reduceLeft { (x, y) => for (a <- x.view; b <- y) yield f(a, b) }
用法:
combine[String](a => b => a + "&" + b)(sets) // curried version
combine[String](_ + "&" + _)(sets) // uncurried version
真棒,谢谢! – dsg 2010-12-23 05:13:42
同步性!在我的解决方案中,将字符串的构造推迟到最后一步,但它们基本相同。 – retronym 2010-05-23 15:59:20