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

后端 未结 3 672
暗喜
暗喜 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)
    

提交回复
热议问题