简体   繁体   English

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

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

Let's say there are three collections: 假设有三个集合:

val numbers = List("1", "2")
val signs = List("-", "+")
val chars = List("a", "b")

I want to generate combinations of elements of those collections. 我想生成这些集合的元素组合。 What I want is not exactly a cartesian product, nor all possible combinations. 我想要的不是确切的笛卡尔积,也不是所有可能的组合。 What I want to have is something like this: 我想要的是这样的:

(1)
(1, -)
(1, -, a)
(1, -, b)
(1, +)
(1, +, a)
(1, +, b)
...

If I could sum this up in a set of formulas, I want to have these sets: 如果我可以将其总结为一组公式,则希望具有以下几组:

numbers
signs
chars
numbers * signs
numbers * chars
signs * chars
numbers * signs * chars

with important note that each of the product can contain only one element from each of the sets. 需要特别注意的是,每种产品只能包含一组元素。 These tuples, for example, would not be something I want in my result: 例如,这些元组不是我想要的结果:

(1, 2, -)
(a, -, +)

because they have two numbers or two signs. 因为它们有两个数字或两个符号。

Any hints on how I could approach this interesting problem? 关于如何解决这个有趣问题的任何提示? I think Python package itertools has product function that deals with this, but I could not find anything similar for Scala. 我认为Python包itertools具有处理此问题的product功能,但是我找不到与Scala类似的东西。

I guess what you want is all possible subsets of elements from those collections, in order and not repeating. 我想您想要的是这些集合中所有可能的元素子集,按顺序排列并且不重复。 You can do something alike: 您可以做类似的事情:

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

Basically, it's a mixing of @jwvh and @Dima's answers. 基本上,这是@jwvh和@Dima的答案的混合。 If you want to obtain tuples instead of lists, you can do: 如果要获取元组而不是列表,则可以执行以下操作:

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

The output: 输出:

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

Recall that this solution is very specific to your problem. 回想一下,该解决方案非常针对您的问题。

"Product" in scala would look something like this: Scala中的“产品”如下所示:

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

That should help you get started hopefully. 这应该可以帮助您入门。

One problem with your request is that tuples of different sizes are actually different types, so you don't want to mix them in a collection. 您的请求的一个问题是,不同大小的元组实际上是不同的类型,因此您不想将它们混合在集合中。

Using a List[List[String]] to express the result, I think this gets at what you want. 我认为使用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

Thanks everyone for hints, I managed to solve the issue. 感谢大家的提示,我设法解决了这个问题。 This is how I did it... 这是我做的...

First I defined a set of collection names, let's call them that way: 首先,我定义了一组集合名称,让我们这样称呼它们:

val set: Set[String] = Set("numbers", "signs", "chars")

In addition to that, I defined their values: 除此之外,我还定义了它们的值:

val valueMap: Map[String, List[String]] = Map("numbers" -> List("1", "2", "3"), "signs" -> List("+", "-"), "chars" -> List("a", "b")

Then I did some mapping and magic: 然后我做了一些映射和魔术:

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

This helped me to get something like this: 这帮助我得到了这样的东西:

Set()
Set(numbers)
Set(signs)
Set(chars)
Set(numbers, signs)
Set(numbers, chars)
Set(signs, chars)
Set(numbers, signs, chars)

After that, I used values of each of those sets from valueMap (each value is List[String] and applied this approach https://stackoverflow.com/a/42095955/589571 to make a recursive cross product of arbitrary number of lists. I needed little more of mapping and gymnastics to get me the structure I wanted to have but in general, this was it. 之后,我使用了valueMap每个集合的值(每个值都是List[String]并应用了此方法https://stackoverflow.com/a/42095955/589571来生成任意数量的列表的递归叉积。我只需要更多的制图和体操就可以得到想要的结构,但总的来说就是这样。

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

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