Generating all possible combinations from a List[List[Int]] in Scala

后端 未结 3 613
暗喜
暗喜 2020-12-16 04:51

Given the following list:

List(List(1,2,3), List(4,5))

I would like to generate all the possible combinations. Using yield, it

相关标签:
3条回答
  • 2020-12-16 05:26

    Here's a recursive solution:

      def generator(x: List[List[Int]]): List[List[Int]] = x match {
        case Nil    => List(Nil)
        case h :: _ => h.flatMap(i => generator(x.tail).map(i :: _))
      }
    

    which produces:

    val a = List(List(1, 2, 3), List(4, 5))       
    val b = List(List(1, 2, 3), List(4, 5), List(6, 7))
    
    generator(a)    //> List(List(1, 4), List(1, 5), List(2, 4), 
                    //| List(2, 5), List(3, 4), List(3, 5))
    generator(b)    //> List(List(1, 4, 6), List(1, 4, 7), List(1, 5, 6), 
                    //| List(1, 5, 7), List(2, 4, 6), List(2, 4, 7),
                    //| List(2, 5, 6), List(2, 5, 7), Listt(3, 4, 6), 
                    //| List(3, 4, 7), List(3, 5, 6), List(3, 5, 7))
    

    Update: the second case can also be written as a for comprehension, which may be a little clearer:

    def generator2(x: List[List[Int]]): List[List[Int]] = x match {
      case Nil    => List(Nil)
      case h :: t => for (j <- generator2(t); i <- h) yield i :: j
    }
    

    Update 2: for larger datasets, if you run out of memory, you can use Streams instead (if it makes sense to process the results incrementally). For example:

    def generator(x: Stream[Stream[Int]]): Stream[Stream[Int]] = 
      if (x.isEmpty) Stream(Stream.empty) 
      else x.head.flatMap(i => generator(x.tail).map(i #:: _))
    
    // NB pass in the data as Stream of Streams, not List of Lists
    generator(input).take(3).foreach(x => println(x.toList))
    
    >List(0, 0, 0, 0, 0, 0, 0)
    >List(0, 0, 0, 0, 0, 200, 0)
    >List(0, 0, 0, 0, 100, 0, 0)
    
    0 讨论(0)
  • 2020-12-16 05:37

    Ezekiel has exactly what I was looking for. This is just a minor tweak of it to make it generic.

      def generateCombinations[T](x: List[List[T]]): List[List[T]] = {
        x match {
          case Nil => List(Nil)
          case h :: _ => h.flatMap(i => generateCombinations(x.tail).map(i :: _))
        }
      }
    
    0 讨论(0)
  • 2020-12-16 05:48

    Feels like your problem can be described in terms of recursion:

    If you have n lists of int: list1 of size m and list2, ... list n

    • generate the X combinations for list2 to n (so n-1 lists)
    • for each combination, you generate m new ones for each value of list1.
    • the base case is a list of one list of int, you just split all the elements in singleton lists.

    so with List(List(1,2), List(3), List(4, 5)) the result of your recursive call is List(List(3,4),List(3,5)) and for each you add 2 combinations: List(1,3,4), List(2,3,4), List(1,3,5), List(2,3,5).

    0 讨论(0)
提交回复
热议问题