0

I'm currently working with Rust and I'm trying to combine two vectors of references into a single vector of values, without consuming an iterator.

Here's the situation: I'm generating vectors by iterating over specific combinations (2 elements from one vector, 2 elements from another vector).

Here's the code I'm currently working with:

use core::iter::Iterator;
use itertools::Itertools;

fn main() {
    let vec_a: Vec<u8> = vec![1, 2, 3];
    let vec_b: Vec<u8> = vec![4, 5, 6];

    // a: Vec<&u8>
    for a in vec_a.iter().combinations(2) {
        // b: Vec<&u8>
        for b in vec_b.iter().combinations(2) {
            // c: Vec<u8> <- a + b
            let c: Vec<u8> = a.clone().into_iter().chain(b).cloned().collect();
            println!("a: {:?}, b: {:?}, c: {:?}", a, b, c);
        }
    }
}

The expected output is as follows:

a: [1, 2], b: [4, 5], c: [1, 2, 4, 5]
a: [1, 2], b: [4, 6], c: [1, 2, 4, 6]
a: [1, 2], b: [5, 6], c: [1, 2, 5, 6]
a: [1, 3], b: [4, 5], c: [1, 3, 4, 5]
a: [1, 3], b: [4, 6], c: [1, 3, 4, 6]
a: [1, 3], b: [5, 6], c: [1, 3, 5, 6]
a: [2, 3], b: [4, 5], c: [2, 3, 4, 5]
a: [2, 3], b: [4, 6], c: [2, 3, 4, 6]
a: [2, 3], b: [5, 6], c: [2, 3, 5, 6]

I've reviewed the following StackOverflow post: Best way to concatenate vectors in Rust, but the solution provided there consumes the Vec and its iterator, which doesn't work in my case.

Could anyone provide guidance on how to combine these vectors of references into a vector of values without consuming the iterator? Any insights or suggestions would be greatly appreciated.

Azriel 1rf
  • 147
  • 11
  • Do you actually want *all* combinations of the two vecs? Your current code produces a subset of possible combinations. – harmic Apr 28 '22 at 05:37
  • I've already read the duplicate link and best answer and 2nd best one does not work in this situation... – Azriel 1rf Apr 28 '22 at 05:57
  • @Dogbert It seems not working. https://gist.github.com/azriel1rf/c5521940d470d612b2d9e85d0e1c197d – Azriel 1rf Apr 28 '22 at 06:04
  • 2
    @Azriel1rf try `sub_a.iter().cloned().chain(sub_b).cloned().collect()` – Dogbert Apr 28 '22 at 06:17
  • @Dogbert Thanks, it worked. Is `iter().cloned()` more efficient than `clone().into_iter()`, right? – Azriel 1rf Apr 28 '22 at 06:32
  • 1
    @Azriel1rf Yes it is (it doesn't clone the vector, only on the fly). But do you need to consume `A` or `B` (or both)? Currently you consume `B` but not `A`. – Chayim Friedman Apr 28 '22 at 09:41
  • 1
    What do you mean y "when using a double loop"? Anyway, what I had in mind was something like `A.iter().chain(&B).copied().copied()` – Chayim Friedman Apr 28 '22 at 10:09
  • @ChayimFriedman Thank you so much. I got it. If both are consumed, the code is as follows? `A.into_iter().chain(B).cloned().collect()` – Azriel 1rf Apr 28 '22 at 10:45
  • 1
    @Azriel1rf Yes (you can replace `cloned()` with `copied()`). – Chayim Friedman Apr 28 '22 at 10:46
  • @ChayimFriedman I got it. The `copy` is better than `clone` in this situation. https://stackoverflow.com/questions/31012923/what-is-the-difference-between-copy-and-clone – Azriel 1rf Apr 28 '22 at 10:48
  • 1
    @Azriel1rf I expect both to be optimized to the same machine code, but I prefer `copied()` because it's more explicit (and may, though rarely, be faster). – Chayim Friedman Apr 28 '22 at 10:49

1 Answers1

1

Thanks to @ChayimFriedman, the issue was resolved by using the copied() method twice in the chain. The copied() method creates an iterator that copies the elements of the original iterator. In this case, it's used to copy the references from the original vectors a and b into the new vector c.

Here's the corrected code:

// a: Vec<&u8>
// b: Vec<&u8>

let c: Vec<u8> = a.iter().chain(&b).copied().copied().collect();
println!("a: {:?}", a);
println!("b: {:?}", b);
Azriel 1rf
  • 147
  • 11