Hello i am stuck with some obvious beginner problem.
I have two vectors and i want to iterate over one of them and if an item fulfills a condition it should be moved into the other vector.
I googled my problem and found many vector functions that do not do what i want.
For example retain deletes the item forever.
In my example i have entities that are saved in a vector for each chunk. If one entity runs over the border of a chunk it should be moved into the vector of 'chunkless_entities'. It will then be sorted back into a chunk later.
//take a chunkless entity and put it into the correct chunk
fn enter_chunk(&mut self, free_entity:Entity){
let chunk_x = free_entity.pos_x as usize/self.chunk_size;
let chunk_y = free_entity.pos_y as usize/self.chunk_size;
//depending on color push into correct chunk array
if free_entity.color == RED{
self.chunks_hunt[[chunk_x, chunk_y]].push(free_entity);
}else{
self.chunks_prey[[chunk_x, chunk_y]].push(free_entity);
}
}
// remove entities from wrong chunks
fn leave_chunk(&mut self){
let mut chunkless_entities = Vec::<Entity>::new();
//for each chunk
for x in 0..1+self.w/self.chunk_size{
for y in 0..1+self.h/self.chunk_size{
//for each entity
self.chunks_prey[[x,y]].iter().for_each(|e|{
//check if it left the chunk
if (e.pos_x as usize) < x*self.chunk_size || (e.pos_x as usize) > (x+1)*self.chunk_size ||
(e.pos_y as usize) < y*self.chunk_size || (e.pos_y as usize) > (y+1)*self.chunk_size {
//entity is not inside the chunk bounds
//now we move it somehow into another vector?
}
});
}
}
//put the lost entities back into a chunk where they belong
for i in 0..chunkless_entities.len(){
self.enter_chunk(chunkless_entities.pop().unwrap());
}
}
It looks like an API close to your needs would be Vec::drain_filter(), sadly that part of the stdlib API hasn't been stabilized yet.
You can, however, use the suggestion in the documentation of that method and use indices:
let chunk = &mut self.chunks_prey[[x, y]];
let mut i = 0;
while i < chunk.len() {
let e = &chunk[i];
if e... {
let taken_e = chunk.swap_remove(i);
chunkless_entities.push(taken_e);
} else {
i += 1;
}
}
// ...
for e in chunkless_entities {
self.enter_chunk(e);
}
Obviously if the order of your entities within a chunk matters, you should use .remove(i) rather than .swap_remove(i), but it doesn't seem to be your case, I suspect.
For mutability, my favorite way I've found (while not idiomatic)to handle a situation like this is to use another Vec to collect the index of each item that should be updated while looping through the collection. From here, you have a collection of entity indices which are out of bounds which you can loop over and modify the Vec without angering the borrow checker, or having to rebuild the whole thing:
let mut entity_indices = vec![];
//for each chunk
for x in 0..1+self.w/self.chunk_size{
for y in 0..1+self.h/self.chunk_size{
//for each entity
self.chunks_prey[[x,y]].iter().enumerate().for_each(|(i, e)|{
//check if it left the chunk
if (e.pos_x as usize) < x*self.chunk_size || (e.pos_x as usize) > (x+1)*self.chunk_size ||
(e.pos_y as usize) < y*self.chunk_size || (e.pos_y as usize) > (y+1)*self.chunk_size {
// add the entity's index to the collection
entity_indices.push(i);
}
});
}
}
for i in entity_indices {
// ...
}