Correct way to swap two elements inside of the jagged array

Using struct

#[derive(Clone)]
pub struct Player {
    pub sex: String,
    pub age: usize,
    pub city: String,
}

I'm trying to swap two randomly chosen elements of two subarrays of the individual:

fn replace_mutation(individual: &mut Vec<Vec<Player>>) {
        // define the generator
        let rng = &mut rand::thread_rng();
        // choose  a pair
        let pair_inds = (0..individual.len()).choose_multiple(rng, 2);
        // restrict max length
        let min_team_len = cmp::min(
            individual[pair_inds[0]].len(),
            individual[pair_inds[1]].len(),
        );
        let n_elements_to_replace = (1..=min_team_len).choose(rng).unwrap();
        let inds_to_replace = (0..min_team_len).choose_multiple(rng, n_elements_to_replace);

        let second_vec_clone = individual[pair_inds[1]].clone();

        for ind_to_replace in inds_to_replace {
            individual[pair_inds[1]][ind_to_replace] =
                individual[pair_inds[0]][ind_to_replace].clone();
            individual[pair_inds[0]][ind_to_replace] = second_vec_clone[ind_to_replace].clone();
        }
    }

So, I'm swapping elements using most obvious way, using clone. There are three clone's, so if Vec's are big enough, that's too expensive. How can I do it more elegant (?) way?
I've tried

 std::mem::swap(
                &mut individual[pair_inds[0]][ind_to_replace],
                &mut individual[pair_inds[1]][ind_to_replace],
            );

but it falls since I can't borrow as mutable more than once at a time

Try the swap method of the slice.

2 Likes

One possible approach would be to mem::take (at least one of) the Vec<Player>s out, then do the swap and then put it back.

With some usage of e. g. split_at_mut, it's also possible to access multiple elements of a slice mutably at the same time, though the case distinctions on which index is larger would be tedious.

There's unstable API get_many_mut that will, if stabilized eventually, help with accessing multiple elements of a slice more conveniently.

2 Likes

Another idea: since the order of the pair_inds elements seems to be irrelevant for the swapping, just sort them (pair_inds.sort()), then slice &mut individual[pair_inds[0]..=pair_inds[1]] and match the result against a slice pattern [ind1, .., ind2] to get mutable access to both elements.

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.