如何在Scala中编写通用组合

时间:2014-04-05 20:59:15

标签: scala functional-programming combinations combinatorics for-comprehension

我在Scala中有一个简单的组合函数:

def combine(t1: List[Int], t2: List[Int]) = {
        for {
            a1 <- t1
            a2 <- t2
        } yield List((1, a1), (2, a2))
    }

对于给定的

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

返回

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

所以我想要一个组合列表(元组),其中第一个元素是索引,第二个元素是域中的值。我希望这个组合是唯一的,这样就不会与两个相同索引的元组组合。

不幸的是,我不知道有多少列表可以合并 如何编写更多通用功能?

1 个答案:

答案 0 :(得分:0)

如果我正确理解了这个问题,结果列表的每个条目都应该是一个List,其中包含与原始List中的元素一样多的元组。也就是说,我认为你基本上都在问如何编写一个&#34;可变长度的理解,&#34;需要的发电机数量取决于参数。

要做到这一点,你可以考虑一下for-comprehension desugars to to to to to to to to to to to :::::::::::

$ cat x.scala
object X extends App {

  // Some lists.
  val t1 = List(1,2)
  val t2 = List(4,5,6)
  val t3 = List(7,8)

  // What I think you expect the output to look like for three lists.
  val result1 =  for ( a1<-t1; a2<-t2; a3<-t3 ) yield List( (1,a1), (2,a2), (3,a3) )
  println(result1)

  // Here's what that desugars to.
  val result2 = t1 flatMap ( a1 => t2 flatMap( a2 => t3 map( a3 => List( (1,a1), (2,a2), (3,a3) ) ) ) )
  println(result2)
  println( result2 == result1 )

  // Here is how to do the same thing when you don't know how many lists there are.
  // We're going to assume there is at least one; you could of course add a check.
  def combine( lists:List[List[Int]], i:Int=1, soFar:List[(Int,Int)]=Nil ):List[List[(Int,Int)]] =
    lists match {
      case head::Nil  =>  head.map    ( x => ( (i,x)::soFar ).reverse )
      case head::rest =>  head.flatMap( x => combine( rest, i+1, (i,x)::soFar ) )
    }

  // Now let's see if that gives us the same answer.
  val result3 = combine( List(t1,t2,t3) )
  println(result3)
  println( result3 == result1 )

}
$ scalac x.scala
$ scala X       
List(List((1,1), (2,4), (3,7)), List((1,1), (2,4), (3,8)), List((1,1), (2,5), (3,7)), List((1,1), (2,5), (3,8)), List((1,1), (2,6), (3,7)), List((1,1), (2,6), (3,8)), List((1,2), (2,4), (3,7)), List((1,2), (2,4), (3,8)), List((1,2), (2,5), (3,7)), List((1,2), (2,5), (3,8)), List((1,2), (2,6), (3,7)), List((1,2), (2,6), (3,8)))
List(List((1,1), (2,4), (3,7)), List((1,1), (2,4), (3,8)), List((1,1), (2,5), (3,7)), List((1,1), (2,5), (3,8)), List((1,1), (2,6), (3,7)), List((1,1), (2,6), (3,8)), List((1,2), (2,4), (3,7)), List((1,2), (2,4), (3,8)), List((1,2), (2,5), (3,7)), List((1,2), (2,5), (3,8)), List((1,2), (2,6), (3,7)), List((1,2), (2,6), (3,8)))
true
List(List((1,1), (2,4), (3,7)), List((1,1), (2,4), (3,8)), List((1,1), (2,5), (3,7)), List((1,1), (2,5), (3,8)), List((1,1), (2,6), (3,7)), List((1,1), (2,6), (3,8)), List((1,2), (2,4), (3,7)), List((1,2), (2,4), (3,8)), List((1,2), (2,5), (3,7)), List((1,2), (2,5), (3,8)), List((1,2), (2,6), (3,7)), List((1,2), (2,6), (3,8)))
true