任意数量集合的元素的Scala组合

时间:2017-12-22 17:06:21

标签: scala

我们假设有三个集合:

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相似的东西。

4 个答案:

答案 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来生成任意数量列表的递归交叉积。我需要更多的绘图和体操来获得我想要的结构,但总的来说,就是这样。