Konstantin Milyutin
Konstantin Milyutin

Reputation: 12366

Query the result of for expression inside the loop

for (i <- Range(1,7); j <- Range(1,7))
  yield (i,j) // want to yield only if there is no such a pair

Is it possible to have access to the list, formed by yield, inside the loop? For example, if I don't want to add duplicates.

P.S. The main question is not how to do it in this particular case. But how to avoid duplicates in more complex case, where I want to check, what was already yielded.

Upvotes: 1

Views: 349

Answers (5)

user unknown
user unknown

Reputation: 36269

I'm not sure, whether you want to prevent pairs of identic entries, or identic pairs, ignoring which comes first.

In the second case, you might use an ordering, and just add cases where a < b or a <= b:

for (i <- Range(1,6); j <- Range(i+1, 7)) yield (i,j)

Upvotes: 1

Dan Simon
Dan Simon

Reputation: 13137

You cannot access members of an immutable collection being built from within the for comprehension.

First of all, I'm going to modify your example so it actually produces duplicates:

for (i <- Range(1,3); j <- Range(1,3)) yield (i min j, i max j)
//scala.collection.immutable.IndexedSeq[(Int, Int)] = Vector((1,1), (1,2), (1,2), (2,2))

For comprehensions are just syntactic sugar, so here's the equivalent using map and flatMap that produces the exact same result

Range(1,3).flatMap{i => Range(1,3).map{ j => (i min j, i max j)}}

As you can see, you're not actually building a single collection, but rather a collection of collections, and then merging them together as they're created. The inner map is taking each j in the range and mapping it to a pair, then the outer flatMap is mapping each i to a sequence of pairs and merging them together. If I change the flatMap to just map, the result is this:

Range(1,3).map{i => Range(1,3).map{ j => (i min j, i max j)}}
//Vector(Vector((1,1), (1,2)), Vector((1,2), (2,2)))

So only after the whole operation is finished can you access the result as a single collection. The result is a Vector which extends IndexedSeq[(Int, Int)], so you can use any of that trait's methods on the result, one of them is distinct:

(for (i <- Range(1,3); j <- Range(1,3)) yield (i min j, i max j)).distinct
//Vector((1,1), (1,2), (2,2))

Upvotes: 3

Infinity
Infinity

Reputation: 3441

for (i <- Range(1,7); j <- Range( i ,7))
  yield (i,j)

Upvotes: -1

0__
0__

Reputation: 67330

Like this

for (i <- Range(1,7); j <- Range(1,7); if i != j ) yield (i,j)

or this

for (i <- Range(1,7); j <- Range(1,7); if i < j ) yield (i,j)

?

Upvotes: 2

Rogach
Rogach

Reputation: 27270

(for {i <- (1 to 7); j <- (1 to 7)} yield (i,j)).distinct

This would return list of tuples without duplicates.

And no, there is no way to have access to the list inside for loop. That would break the functional programming, after all.

Upvotes: 1

Related Questions