簡體   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