[ACCEPTED]-Scala - can yield be used multiple times with a for loop?-cartesian-product
It's not clear what you're asking for - what 10 you expect the semantics of multiple yield 9 to be. One thing, though, is that you probably 8 never want to use indexes to navigate a 7 list - each call to t(i) is O(i) to execute.
So 6 here's one possibility that you might be 5 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 4 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 3 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 2 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 1 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)
No, you can't use multiple yield clauses, but 5 there are work-arounds. For example:
for (i <- 0 to 10;
r <- List(l(i), t(i)))
yield r
You 4 can nest for-comprehensions, of course, but 3 that would result in a list of lists of 2 elements, which I don't believe is what 1 you want.
Yields can be nested, which would result 2 ...
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 1 solution is semantically different.
Here is a type-agnostic solution for an 4 unknown, varying number of elements in a 3 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 2 overengineered. You could although call 1 it
xproduct (List (l, t))
Apparently not. I get a compile error when 5 I try it.
It looks like for .. yield is 4 an expression. You can't have two yields, since 3 that's not really part of the expression.
If 2 you want to yield multiple values, why not 1 yield them as a tuple or a list?
For example:
for( t <- List(1,2,3); l <- List(-1,-2,-3))
yield (t, l)
Maybe yield is not the best way to go? Perhaps 1 simple array appending could be used here.
More Related questions
We use cookies to improve the performance of the site. By staying on our site, you agree to the terms of use of cookies.