【问题标题】:Scala - can yield be used multiple times with a for loop?Scala - 可以通过 for 循环多次使用 yield 吗?
【发布时间】:2010-11-11 12:40:44
【问题描述】:

一个例子:

val l = List(1,2,3)
val t = List(-1,-2,-3)

我可以这样做吗?

for (i <- 0 to 10) yield (l(i)) yield (t(i))

基本上我想为每次迭代产生多个结果。

【问题讨论】:

    标签: scala yield cartesian-product


    【解决方案1】:

    不清楚您要的是什么 - 您期望多重 yield 的语义是什么。不过,有一件事是您可能永远不想使用索引来导航列表 - 对 t(i) 的每次调用都是 O(i) 来执行的。

    所以这是您可能要求的一种可能性

    scala> val l = List(1,2,3); val t = List(-1,-2,-3)
    l: List[Int] = List(1, 2, 3)
    t: List[Int] = List(-1, -2, -3)
    
    scala> val pairs = l zip t
    pairs: List[(Int, Int)] = List((1,-1), (2,-2), (3,-3))
    

    这是您可能要求的另一种可能性

    scala> val crossProduct = for (x <- l; y <- t) yield (x,y)
    crossProduct: List[(Int, Int)] = List((1,-1), (1,-2), (1,-3), (2,-1), (2,-2), (2,-3), (3,-1), (3,-2), (3,-3))
    

    后者只是语法糖

    scala> val crossProduct2 = l flatMap {x => t map {y => (x,y)}}
    crossProduct2: List[(Int, Int)] = List((1,-1), (1,-2), (1,-3), (2,-1), (2,-2), (2,-3), (3,-1), (3,-2), (3,-3))
    

    第三种可能是你想交错它们

    scala> val interleaved = for ((x,y) <- l zip t; r <- List(x,y)) yield r
    interleaved: List[Int] = List(1, -1, 2, -2, 3, -3, 4, -4, 5, -5, 6, -6, 7, -7, 8, -8, 9, -9, 10, -10)
    

    这是语法糖

    scala> val interleaved2 = l zip t flatMap {case (x,y) => List(x,y)}
    interleaved2: List[Int] = List(1, -1, 2, -2, 3, -3, 4, -4, 5, -5, 6, -6, 7, -7, 8, -8, 9, -9, 10, -10)
    

    【讨论】:

    • 我认为他只是想插入列表。
    • 对,我想交错它们,所以这两个给出相同的结果: [James] val interleaved = for ((x,y)
    【解决方案2】:

    不,您不能使用多个 yield 子句,但有一些变通方法。例如:

    for (i <- 0 to 10;
         r <- List(l(i), t(i)))
    yield r
    

    当然,您可以嵌套 for-comprehensions,但这会产生一个元素列表列表,我认为这不是您想要的。

    【讨论】:

    • 警告,这个解决方案是 O(n^2)
    • 对于 l&t 列表,我承认,这是他的例子。如果 t&l 是数组或函数,那就不是这样了,对吧?
    • 对,数组索引访问是 O(1),所以解决方案是 O(n)。
    【解决方案3】:

    产量可以嵌套,这将导致...

    for (i <- 0 to 3) yield {
      for (j <- 0 to 2) yield (i,j)
    }
    

    在向量的向量中:

    scala.collection.immutable.IndexedSeq[scala.collection.immutable.IndexedSeq[(Int, Int)]]
    = Vector(Vector((0,0), (0,1), (0,2)), Vector((1,0), (1,1), (1,2)), Vector((2,0), (2,1), (2,2)), Vector((3,0), (3,1), (3,2)))
    
    for (i <- 0 to 3;
      j <- 0 to 2) yield (i,j)
    

    扁平化解决方案在语义上是不同的。

    【讨论】:

      【解决方案4】:

      对于未知数量的列表中的未知、不同数量的元素,这是一个与类型无关的解决方案:

      def xproduct (xx: List [List[_]]) : List [List[_]] = 
        xx match {
          case aa :: bb :: Nil => 
            aa.map (a => bb.map (b => List (a, b))).flatten       
          case aa :: bb :: cc => 
            xproduct (bb :: cc).map (li => aa.map (a => a :: li)).flatten
          case _ => xx
      }
      

      对于 2 个列表,它是过度设计的。你可以虽然叫它

         xproduct (List (l, t))
      

      【讨论】:

        【解决方案5】:

        显然不是。尝试时出现编译错误。

        看起来 for .. yield 是一个表达式。你不能有两个 yield,因为这不是表达式的一部分。

        如果要产生多个值,为什么不将它们作为元组或列表产生呢?

        例如:

        for( t <- List(1,2,3); l <- List(-1,-2,-3))
          yield (t, l)
        

        【讨论】:

          【解决方案6】:

          也许 yield 不是最好的方法?也许在这里可以使用简单的数组附加。

          【讨论】:

          • 使用yield和使用列表在语义上没有区别。实际差异涉及内存使用,其中 yield 对于大型集合更有效。
          猜你喜欢
          • 2014-12-20
          • 2011-05-11
          • 2016-06-19
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2016-01-02
          • 1970-01-01
          • 2018-03-11
          相关资源
          最近更新 更多