How to mutate items of a vector during iteration? [duplicate] - vector

This question already has answers here:
Efficiently mutate a vector while also iterating over the same vector
(2 answers)
Closed 2 years ago.
I have a Vec of structs. When iterating over this Vec using .iter() I want to edit each element inside a for loop, but I'm getting an error that says each element is already borrowed, how can I solve this? Here's a small code example:
struct complex_struct {
attr1: i32
}
let elements: Vec<complex_struct> = generate_data();
for element in elements.iter() {
element.attr1 = 0;
}

Use the iter_mut to get mutable elements out of the iterator:
#[derive(Debug)]
struct ComplexStruct {
attr1: i32
}
fn main() {
let mut elements: Vec<ComplexStruct> = vec![ComplexStruct { attr1: 5 }];
for element in elements.iter_mut() {
element.attr1 = 0;
}
dbg!(elements); // prints out [ComplexStruct { attr1: 0 }]
}
playground

Related

How can I keep track of the smallest entry in a collection? [duplicate]

This question already has answers here:
Why can't I store a value and a reference to that value in the same struct?
(4 answers)
How do I create a BinaryHeap that pops the smallest value, not the largest?
(2 answers)
Take element with lowest value from a HashSet?
(1 answer)
How to get the minimum value within a vector in Rust?
(3 answers)
What is the idiomatic way to get the index of a maximum or minimum floating point value in a slice or Vec in Rust?
(5 answers)
Closed 1 year ago.
I have a toy app where I can add entries to a collection, but I cannot modify the add method to keep track of the smallest entry.
The basic version is here
I think I need to add something like a smallest_entry: Option<&'a Entry> to the struct that holds the entries, but I cannot figure out how to modify the add_entry
the data structure is
struct Entry {
pub value: usize,
}
struct Source {
pub entries: Vec<Entry>,
// pub smallest_entry: Option<&'a Entry>,
}
struct SourcesRepository {
pub map: HashMap<String, Source>,
}
and the current add_entry method is
impl SourcesRepository {
fn add_entry(&mut self, title: String, entry: Entry) {
match self.map.get_mut(&title) {
Some(source) => {
// we already have a Source for this title: add new entry to it
source.entries.push(entry);
}
None => {
// no source existing for this title: create new and add entry
let mut source = Source {
entries: Vec::new(),
};
source.entries.push(entry);
self.map.insert(title, source);
}
}
}
}
I imagine once I have the source entry I should compare it with the smallest_entry and update that reference if the new entry is smaller. I've tried to modify the code but I cannot make the lifetimes work.
impl SourcesRepository<'_> {
fn add_entry(&mut self, title: String, entry: Entry) {
match self.map.get_mut(&title) {
Some(source) => {
// we already have a Source for this title: add new entry to it
match source.smallest_entry {
Some(smallest_entry) => {
if entry.value < smallest_entry.value {
source.smallest_entry = Some(&entry);
}
}
None => {
source.smallest_entry = Some(&entry);
}
}
source.entries.push(entry);
}
None => {
// no source existing for this title: create new and add entry
let mut source = Source {
entries: Vec::new(),
smallest_entry: Some(&entry),
};
source.entries.push(entry);
self.map.insert(title, source);
}
}
}
}
link to broken version

Is it possible to have a uniform Iterator interface for different data structures in rust? [duplicate]

This question already has answers here:
Conditionally iterate over one of several possible iterators
(4 answers)
Closed 2 years ago.
I want have something like below
use std::collections::HashMap;
pub enum DiffStruct {
V(Vec<i32>),
M(HashMap<i32,i32>),
}
impl DiffStruct {
fn to_iter(self) -> impl IntoIterator<Item = i32> {
match self {
DiffStruct::V(vec) => vec.iter().into_iter(),
DiffStruct::M(map) => map.values().into_iter(),
}
}
}
fn main() {
let v: Vec<_> = DiffStruct::V(vec![1,2,3]).to_iter().collect();
}
playground
So that I can minimize the collect behavior of my code for best performance, but it does not compile, any workaround to achieve this?
Assuming you want to take ownership of DiffStruct and not just borrow it when you collect its values:
use std::collections::HashMap;
pub enum DiffStruct {
V(Vec<i32>),
M(HashMap<i32,i32>),
}
impl DiffStruct {
fn to_iter(self) -> Box<dyn Iterator<Item = i32>> {
match self {
DiffStruct::V(vec) => Box::new(vec.into_iter()),
DiffStruct::M(map) => Box::new(map.into_iter().map(|(_, v)| v)),
}
}
}
fn main() {
let vec_values = vec![1, 2, 3];
let mut map_values = HashMap::new();
map_values.insert(1, 1);
map_values.insert(2, 2);
map_values.insert(3, 3);
let ds_vec = DiffStruct::V(vec_values);
let ds_map = DiffStruct::M(map_values);
let collected_from_vec: Vec<_> = ds_vec.to_iter().collect();
let collected_from_map: Vec<_> = ds_map.to_iter().collect();
}
playground
See also
Conditionally iterate over one of several possible iterators
What is the correct way to return an Iterator?

Fill a vector of struct elements by iteration rather than using .push() one by one

I am trying to find an elegant way to fill a vector of struct elements with a loop or logic instead of writing one .push() for every element I create.
The struct element is a question with many more fields than in the following example and the instances need to be mutable because they are modified by user input :
struct Question {
id: usize,
question: String,
}
fn main() {
//A large and growing list of questions
let mut q0 = Question {
id: 0,
question: String::from("A field I fill in manually"),
};
// .
// .
// .
let mut q100 = Question {
id: 100,
question: String::from("Another field, each one is different"),
};
let total_questions: usize = 100;
let mut w: Vec<String> = Vec::new();
for a in 0..total_questions {
let s = format!("q{}", a);
w.push(s);
}
//w contains ["q0", "q1", ..., "q100"] but is of type std::string::String
let mut v: Vec<&mut Question> = Vec::new();
//Expects type struct `main::Question`
//I would like to avoid :
v.push(&mut q0);
v.push(&mut q1);
// .
// .
// .
v.push(&mut q100);
}
I am not sure that in my example the w: Vec<String> is of any use.
I have looked into .collect() but could not understand how to utilize it in my case.
I'd be happy to be pointed towards a similar question if this is a duplicate I have not found one.
Edit : I have changed the structs string content as it was misleading. They each contain Strings that are unique and cannot be generated. I also realized that Stack Overflow automatically included this in a some_fn() function when we are actually inside main()
The problem is because you don't have any data structure that contains the Questions -- you just have 100+ independent local variables -- it's not possible to iterate over them to fill the Vec. You can fix this by putting all the Questions in a Vec<Question> as you create them. Here's an example:
let mut v: Vec<Question> = vec![
Question {
id: 0,
question: String::from("Q0"),
},
// ...
Question {
id: 100,
question: String::from("Q100"),
},
];
In fact, once you do this you probably don't need the Vec<&mut Question> at all, since you can mutate the questions directly by indexing v. However, if you do need the vector of references for some reason, you can create it by collecting an iterator:
let v_refs: Vec<&mut Question> = v.iter_mut().collect();
If you can generate your Question object with a function you can use an iterator. Here is an example which just generates numbered Question objects out of a numeric range:
struct Question {
id: usize,
question: String,
}
fn main() {
let v: Vec<Question> = (0..10)
.map(|x| Question {
id: x,
question: "Q".to_string() + &x.to_string(),
})
.collect();
for x in &v {
println!("{}: {}", x.id, x.question);
}
}
Here is an example where you get the strings from an array of strings:
struct Question<'a> {
id: usize,
question: &'a str,
}
const QUESTIONS: [&str; 3] = ["A", "B", "C"];
fn main() {
let v: Vec<Question> = (0..questions.len())
.map(|x| Question {
id: x,
question: questions[x],
})
.collect();
for x in &v {
println!("{}: {}", x.id, x.question);
}
}

What is the paradigmatic way to create a Rust tree with a parent pointer? [duplicate]

This question already has answers here:
How do I express mutually recursive data structures in safe Rust?
(4 answers)
How to model complex recursive data structures (graphs)?
(1 answer)
Why can't I store a value and a reference to that value in the same struct?
(4 answers)
Closed 5 years ago.
The community reviewed whether to reopen this question last month and left it closed:
Original close reason(s) were not resolved
I need to define a binary search tree where each node has access to the parent:
enum Tree<'a> {
Leaf,
Node {
left: Box<Tree<'a>>,
right: Box<Tree<'a>>,
parent: &'a Tree<'a>,
data: u64,
}
}
impl <'a> Tree<'a> {
pub fn new(data: u64, parent: &'a Tree) -> Tree<'a> {
Tree::Node {
left: Box::new(Tree::Leaf),
right: Box::new(Tree::Leaf),
parent,
data
}
}
pub fn insert_at_left_leaf(&'a mut self, data: u64) {
match *self {
Tree::Leaf => panic!("Leaf has no children"),
Tree::Node {ref mut left, ..} => {
**left = Tree::new(data, self);
}
}
}
}
fn main() {
let parent = Tree::Leaf;
let mut t = Tree::Node {
left: Box::new(Tree::Leaf),
right: Box::new(Tree::Leaf),
parent: &parent,
data: 1u64
};
t.insert_at_left_leaf(2);
}
playground
However, I get the following compilation error:
error[E0502]: cannot borrow `*self` as immutable because `self.left` is also borrowed as mutable
--> src/main.rs:24:42
|
23 | Tree::Node {ref mut left, ..} => {
| ------------ mutable borrow occurs here
24 | **left = Tree::new(data, self);
| ^^^^ immutable borrow occurs here
25 | }
26 | }
| - mutable borrow ends here
What is the paradigmatic way to do this in safe Rust? Specifically, when I insert a new node as the leaf of an existing node, I do not want to re-allocate space for it. There is already space allocated for the Leaf and I want to simply overwrite it with the new node.

How do I process a range in slices in Rust?

I understand that the preferred way to iterate in Rust is through the for var in (range) syntax, but sometimes I'd like to work on more than one of the elements in that range at a time.
From a Ruby perspective, I'm trying to find a way of doing (1..100).each_slice(5) do |this_slice| in Rust.
I'm trying things like
for mut segment_start in (segment_size..max_val).step_by(segment_size) {
let this_segment = segment_start..(segment_start + segment_size).iter().take(segment_size);
}
but I keep getting errors that suggest I'm barking up the wrong type tree. The docs aren't helpful either--they just don't contain this use case.
What's the Rust way to do this?
Use chunks (or chunks_mut if you need mutability):
fn main() {
let things = [5, 4, 3, 2, 1];
for slice in things.chunks(2) {
println!("{:?}", slice);
}
}
Outputs:
[5, 4]
[3, 2]
[1]
The easiest way to combine this with a Range would be to collect the range to a Vec first (which dereferences to a slice):
fn main() {
let things: Vec<_> = (1..100).collect();
for slice in things.chunks(5) {
println!("{:?}", slice);
}
}
Another solution that is pure-iterator would be to use Itertools::chunks_lazy:
extern crate itertools;
use itertools::Itertools;
fn main() {
for chunk in &(1..100).chunks_lazy(5) {
for val in chunk {
print!("{}, ", val);
}
println!("");
}
}
Which suggests a similar solution that only requires the standard library:
fn main() {
let mut range = (1..100).peekable();
while range.peek().is_some() {
for value in range.by_ref().take(5) {
print!("{}, ", value);
}
println!("");
}
}
One trick is that Ruby and Rust have different handling here, mostly centered around efficiency.
In Ruby Enumerable can create new arrays to stuff values in without worrying about ownership and return a new array each time (check with this_slice.object_id).
In Rust, allocating a new vector each time would be pretty unusual. Additionally, you can't easily return a reference to a vector that the iterator holds due to complicated lifetime concerns.
A solution that's very similar to Ruby's is:
fn main() {
let mut range = (1..100).peekable();
while range.peek().is_some() {
let chunk: Vec<_> = range.by_ref().take(5).collect();
println!("{:?}", chunk);
}
}
Which could be wrapped up in a new iterator that hides the details:
use std::iter::Peekable;
struct InefficientChunks<I>
where I: Iterator
{
iter: Peekable<I>,
size: usize,
}
impl<I> Iterator for InefficientChunks<I>
where I: Iterator
{
type Item = Vec<I::Item>;
fn next(&mut self) -> Option<Self::Item> {
if self.iter.peek().is_some() {
Some(self.iter.by_ref().take(self.size).collect())
} else {
None
}
}
}
trait Awesome: Iterator + Sized {
fn inefficient_chunks(self, size: usize) -> InefficientChunks<Self> {
InefficientChunks {
iter: self.peekable(),
size: size,
}
}
}
impl<I> Awesome for I where I: Iterator {}
fn main() {
for chunk in (1..100).inefficient_chunks(5) {
println!("{:?}", chunk);
}
}
Collecting into a vec can easily kill your performance. An approach similar to in the question is perfectly fine.
fn chunk_range(range: Range<usize>, chunk_size: usize) -> impl Iterator<Item=Range<usize>> {
range.clone().step_by(chunk_size).map(move |block_start| {
let block_end = (block_start + chunk_size).min(range.end);
block_start..block_end
})
}

Resources