I would like to iterate over the Cartesian product of every pair of elements in a list:
let x = vec![1, 2, 3, 4];
for i in 0..3 {
for j in i + 1..4 {
println!("{} {}", x[i], x[j]);
}
}
1 2
1 3
1 4
2 3
2 4
3 4
So far so good. I wanted to attempt the same thing with an iterator. My idea was to grab an iterator for the outer loop, then clone and skip one element for the inner loop. This did not work well:
let outer = x.iter();
for pt1 in outer.clone() {
for pt2 in (&outer).clone().skip(1) {
println!("{} {}", pt1, pt2);
}
}
Since I had to clone the outer iterator to tee it, the inner is going off the original state, not the current state of the outer iterator:
1 2
1 3
1 4
2 2
2 3
2 4
3 2
3 3
3 4
4 2
4 3
4 4
How can I tell rust to replicate the behavior of the range loops with non-consuming iterators over the elements of the collection?
Related question I found, but the answer still uses iterators over ranges instead of the items themselves: How do I idiomatically compare each item in a list to every other item?.
@brian61354270 already mentioned in the comments, that what you want is not really a cartesian product. Otherwise an obvious answer would be to use
itertools::iproduct!.Going off of your main question:
Since we can assume
x: Vec, and you want to produce indices. Then we can produce a cartesian product of the indices using the range0..x.len().Now, to get the combinations then we can modify it just slightly (similarly to your
+ ifor loop):Then iterating over
indices:Will produce:
Alternatively, you can also use
itertools'scombinations()to achieve the same:Since you don't want to map indices to items, then you could do something like this:
Alternatively, written like this:
Where iterating
for (x, y) in pairsyields the same as before.I would however consider both a lot harder to read. At least when compared to using
indicesand then.map(|(i0, i1)| (x[i0], x[i1])).