Scala - can yield be used multiple times with a for loop?

前端 未结 6 2189
-上瘾入骨i
-上瘾入骨i 2020-12-10 11:56

An example:

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

Can I do something like this?

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


        
相关标签:
6条回答
  • 2020-12-10 12:06

    It's not clear what you're asking for - what you expect the semantics of multiple yield to be. One thing, though, is that you probably never want to use indexes to navigate a list - each call to t(i) is O(i) to execute.

    So here's one possibility that you might be asking for

    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))
    

    And here's another possibility that you might be asking for

    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))
    

    The later is just syntactic sugar for

    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))
    

    A third possibility is you want to interleave them

    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)
    

    That's syntax sugar for

    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)
    
    0 讨论(0)
  • 2020-12-10 12:12

    Maybe yield is not the best way to go? Perhaps simple array appending could be used here.

    0 讨论(0)
  • 2020-12-10 12:16

    Here is a type-agnostic solution for an unknown, varying number of elements in a unknown number of lists:

    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
    }
    

    For 2 Lists it is overengineered. You could although call it

       xproduct (List (l, t))
    
    0 讨论(0)
  • 2020-12-10 12:20

    No, you can't use multiple yield clauses, but there are work-arounds. For example:

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

    You can nest for-comprehensions, of course, but that would result in a list of lists of elements, which I don't believe is what you want.

    0 讨论(0)
  • 2020-12-10 12:21

    Yields can be nested, which would result ...

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

    in a Vector of Vector:

    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)
    

    The flattened solution is semantically different.

    0 讨论(0)
  • 2020-12-10 12:28

    Apparently not. I get a compile error when I try it.

    It looks like for .. yield is an expression. You can't have two yields, since that's not really part of the expression.

    If you want to yield multiple values, why not yield them as a tuple or a list?

    For example:

    for( t <- List(1,2,3); l <- List(-1,-2,-3))
      yield (t, l)
    
    0 讨论(0)
提交回复
热议问题