我们假设有三个集合:
val numbers = List("1", "2")
val signs = List("-", "+")
val chars = List("a", "b")
我想生成这些集合的元素组合。 我想要的不仅仅是笛卡尔积,也不是所有可能的组合。我想拥有的是这样的:
(1)
(1, -)
(1, -, a)
(1, -, b)
(1, +)
(1, +, a)
(1, +, b)
...
如果我可以在一组公式中总结一下,我想要这些集合:
numbers
signs
chars
numbers * signs
numbers * chars
signs * chars
numbers * signs * chars
重要提示,每个产品只能包含每个产品中的一个元素。 例如,这些元组在我的结果中不是我想要的东西:
(1, 2, -)
(a, -, +)
因为他们有两个数字或两个符号。
有关如何处理这个有趣问题的任何提示?
我认为Python包itertools有product
函数可以解决这个问题,但我找不到任何与Scala相似的东西。
答案 0 :(得分:1)
我想你想要的是这些集合中所有可能的元素子集,按顺序而不是重复。你可以做同样的事情:
val res: List[List[String]] = (for (x <- numbers) yield List(x)) ++
(for { x <- numbers; y <- signs } yield List(x,y)) ++
(for { x <- numbers; y <- signs; z <- chars } yield List(x, y, z))
基本上,这是@jwvh和@Dima答案的混合。如果要获取元组而不是列表,可以执行以下操作:
res.map(s => s match {
case List(c) => (c)
case List(x, y) => (x, y)
case List(x,y,z) => (x,y,z)
case _ => (s)
})
输出:
scala> res.map(s => s match { case List(c) => (c); case List(x, y) =>
(x,y); case List(x,y,z) => (x,y,z); case _ => (s) })
res21: List[java.io.Serializable] = List(1, 2, (1,-), (1,+), (2,-), (2,+),
(1,-,a), (1,-,b), (1,+,a), (1,+,b), (2,-,a), (2,-,b), (2,+,a), (2,+,b))
回想一下,此解决方案非常适合您的问题。
答案 1 :(得分:0)
&#34;产品&#34;在scala看起来像这样:
for {
n <- numbers
s <- signs
c <- chars
} yield (n, s, c)
这应该可以帮助你有条不紊地开始。
答案 2 :(得分:0)
您的请求存在的一个问题是,不同大小的元组实际上是不同的类型,因此您不希望将它们混合在一个集合中。
使用List[List[String]]
来表达结果,我认为这可以达到你想要的效果。
val numbers = List("1", "2")
val signs = List("-", "+")
val chars = List("a", "b")
numbers.flatMap{n =>
List(n) :: signs.flatMap{s =>
List(s) :: List(n,s) :: chars.flatMap{c =>
List(List(c), List(n,c), List(s,c), List(n,s,c))
}
}
}.distinct
答案 3 :(得分:0)
感谢大家的提示,我设法解决了这个问题。我就这样做了......
首先我定义了一组集合名称,让我们这样称呼它们:
val set: Set[String] = Set("numbers", "signs", "chars")
除此之外,我还定义了他们的价值观:
val valueMap: Map[String, List[String]] = Map("numbers" -> List("1", "2", "3"), "signs" -> List("+", "-"), "chars" -> List("a", "b")
然后我做了一些映射和魔术:
val kpiComboPhase1 = set.subsets.toList.map(aSet => {
aSet.toList.flatMap(el => valueMap.get(el))
})
val kpiComboPhase2 = kpiComboPhase1.map(l => {
if (l.length === 1) l.flatten else l
})
这帮助我得到了这样的东西:
Set()
Set(numbers)
Set(signs)
Set(chars)
Set(numbers, signs)
Set(numbers, chars)
Set(signs, chars)
Set(numbers, signs, chars)
之后,我使用valueMap
中每个集合的值(每个值为List[String]
并应用此方法https://stackoverflow.com/a/42095955/589571来生成任意数量列表的递归交叉积。我需要更多的绘图和体操来获得我想要的结构,但总的来说,就是这样。