Listing combinations WITH repetitions in Scala

后端 未结 7 829
盖世英雄少女心
盖世英雄少女心 2021-01-12 01:18

Trying to learn a bit of Scala and ran into this problem. I found a solution for all combinations without repetions here and I somewhat understand the idea behind i

相关标签:
7条回答
  • 2021-01-12 01:42

    It is really not clear what you are asking for. It could be one of a few different things. First would be simple combinations of different elements in a list. Scala offers that with the combinations() method from collections. If elements are distinct, the behavior is exactly what you expect from classical definition of "combinations". For n-element combinations of p elements there will be p!/n!(p-n)! combinations in the output.

    If there are repeated elements in the list, though, Scala will generate combinations with the item appearing more than once in the combinations. But just the different possible combinations, with the element possibly replicated as many times as they exist in the input. It generates only the set of possible combinations, so repeated elements, but not repeated combinations. I'm not sure if underlying it there is an iterator to an actual Set.

    Now what you actually mean if I understand correctly is combinations from a given set of different p elements, where an element can appear repeatedly n times in the combination.

    Well, coming back a little, to generate combinations when there are repeated elements in the input, and you wanna see the repeated combinations in the output, the way to go about it is just to generate it by "brute-force" using n nested loops. Notice that there is really nothing brute about it, it is just the natural number of combinations, really, which is O(p^n) for small n, and there is nothing you can do about it. You only should be careful to pick these values properly, like this:

    val a = List(1,1,2,3,4)
    def comb = for (i <- 0 until a.size - 1; j <- i+1 until a.size) yield (a(i), a(j))
    

    resulting in

    scala> comb
    res55: scala.collection.immutable.IndexedSeq[(Int, Int)] = Vector((1,1), (1,2), (1,3), (1,4), (1,2), (1,3), (1,4), (2,3), (2,4), (3,4))
    

    This generates the combinations from these repeated values in a, by first creating the intermediate combinations of 0 until a.size as (i, j)...

    Now to create the "combinations with repetitions" you just have to change the indices like this:

    val a = List('A','B','C')
    def comb = for (i <- 0 until a.size; j <- i until a.size) yield (a(i), a(j))
    

    will produce

    List((A,A), (A,B), (A,C), (B,B), (B,C), (C,C))
    

    But I'm not sure what's the best way to generalize this to larger combinations.

    Now I close with what I was looking for when I found this post: a function to generate the combinations from an input that contains repeated elements, with intermediary indices generated by combinations(). It is nice that this method produces a list instead of a tuple, so that means we can actually solve the problem using a "map of a map", something I'm not sure anyone else has proposed here, but that is pretty nifty and will make your love for FP and Scala grow a bit more after you see it!

    def comb[N](p:Seq[N], n:Int) = (0 until p.size).combinations(n) map { _ map p }
    

    results in

    scala> val a = List('A','A','B','C')
    scala> comb(a, 2).toList
    res60: List[scala.collection.immutable.IndexedSeq[Int]] = List(Vector(1, 1), Vector(1, 2), Vector(1, 3), Vector(1, 2), Vector(1, 3), Vector(2, 3))
    
    0 讨论(0)
提交回复
热议问题