繁体   English   中英

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

[英]Scala combination of elements of arbitrary number of collections

假设有三个集合:

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

我想您想要的是这些集合中所有可能的元素子集,按顺序排列并且不重复。 您可以做类似的事情:

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))

回想一下,该解决方案非常针对您的问题。

Scala中的“产品”如下所示:

 for {
  n <- numbers
  s <- signs
  c <- chars
 } yield (n, s, c)

这应该可以帮助您入门。

您的请求的一个问题是,不同大小的元组实际上是不同的类型,因此您不想将它们混合在集合中。

我认为使用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

感谢大家的提示,我设法解决了这个问题。 这是我做的...

首先,我定义了一组集合名称,让我们这样称呼它们:

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM