0

In Rust, I have a Vec of Vec. I want to merge the content of one sub Vec with another one.

Here is my code:

let mut a = vec![vec![1, 2, 3], vec![3, 4, 5, 6], vec![8, 9]];
a[0].append(&mut a[1]);
assert_eq!(&a, &[vec![1, 2, 3, 3, 4, 5, 6], vec![], vec![8, 9]])

The issue is that I cannot borrow twice a as mutable. What is the most efficient and idiomatic way to solve it?

Boiethios
  • 38,438
  • 19
  • 134
  • 183
user2655800
  • 141
  • 10
  • 1
    Or you can swap memory: `let tmp = std::mem::replace(&mut a[1], Vec::new())`: https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=5801bfb3cefe43a13ef6dc774d2daf84. Either way, that's a duplicate. – Boiethios Jan 15 '19 at 11:08
  • 1
    @Boiethios, I don't think it is what OP's need. The need was checking the containing vectors were need to be trailed so there needs to be element matching with the last and first elements. I am not sure the edit and the playground link is appropriate for the OP's need since the vectors are replaced with mem::replace index as hardcoded – Akiner Alkan Jan 15 '19 at 11:14
  • 1
    @AkinerAlkan Well, I'm not here to guess. If the OP wants to do this, let he update the question. – Boiethios Jan 15 '19 at 11:25
  • @Boiethios, you are right, So I am leaving my answer as it is, and let's say if the OP really have the needs as asked in the beginning then he can use my answer, If it's not, your playground link will be the more simple and reasonable solution – Akiner Alkan Jan 15 '19 at 11:28
  • @Boiethios @AkinerAlkan Sorry, I changed my question to a simpler one while you were writing your response. To both simplified and full question the `std::mem::replace` function solves my issue. – user2655800 Jan 15 '19 at 14:24

2 Answers2

2

You can implement it in a one loop with using fold

fn main() {
    let mut a = vec![vec![1, 2, 3], vec![3, 4, 5, 6], vec![8, 9]];

    a.iter_mut()
        .fold(&mut Vec::new(), |previous_vec, current_vec| {
            if previous_vec.len() > 0
                && current_vec.len() > 0
                && previous_vec.last() == current_vec.first()
            {
                previous_vec.append(current_vec);
                return previous_vec;
            }
            current_vec
        });

    assert_eq!(a, vec![vec![1, 2, 3, 3, 4, 5, 6], vec![], vec![8, 9]]);
}

You can test it in Playground

Akiner Alkan
  • 6,145
  • 3
  • 32
  • 68
0

I think best solution to use extend with iter or drain iterators

    let mut v1 = vec![1,2,3];
    let mut v2 = vec![3,4,5];

    if v1[v1.len()-1] == v2[0] {
        v1.extend(v2[1..].iter()); // clones elemts
        println!("{:?}", v1);
        v1.extend(v2.drain(1..)); // drained from second vector this time
        println!("{:?}", v2);
    }

Live example

you pass slice to extend and if you want them to be moved use drain or iter for cloning. Not drained elements will be left in second vector.

Upd: with changes you made to the question you probably should just move inner vec to some temporary vec after checking and then merge it with extend

Sugar
  • 490
  • 9
  • 22