How to iterate elements of a hashmap over themselves and have them be mutable?

Viewed 291

So I have a hashmap that uses strings as keys and the values are my own struct for users. Which is just their name and position

pub struct User {
    name: String,
    x: i32,
    y: i32
}

Now what I want to do is iterate over the hashmap called users and see if two users position are close to each other, and then move them apart.

for (key, userA) in self.users.iter_mut() {
    for (key, userB) in self.users.iter_mut() {
        // collision code would go in here
    }
}

This causes an issue because users are then borrowed twice as mutable. I thought of getting around this issue by using mutex,

for (key, userA) in self.users.lock().unwrap().iter_mut() {
    for (key, userB) in self.users.lock().unwrap().iter_mut() {
        // collision code would go in here
    }
}

and the code compiles but it causes a runtime error later when I actually add an user to the map because of the second loop, since if I comment that loop out, the code runs with no issues. Any ideas on how I could write this differently?

1 Answers

You could do this in two stages. First you collect the collisions, and then resolve them. As an example:

let mut collisions = Vec::new();
for (key_a, user_a) in self.users.iter() {
    for (key_b, user_b) in self.users.iter() {
        if key_a == key_b {
            continue;
        }

        if user_a.x == user_b.x && user_a.y == user_b.y {
            collisions.push((key_a, key_b));
        }
    }
}

for (key_a, key_b) in collisions {
    // Move users apart.
}
Related