How to iterate inside an iteration? - rust

So basically, I want to do this
for i=0;i<x.len()-1
for j=i;j<x.len
//do stuff with x[j] and x[i] at the same time
For example, I want to use the same tehnique as sorting using 2 for loops, comparing element with element and interchange them. I do not want to sort however, just gave this example for better understanding.
Can i somehow do like:
for x in vec.iter()
for y in x.next()
or something like this?
Also, can I somehow remember the position of a certain element while iterating?
Thank you!

You could use ranges
for i in 0..vec.len()-1 {
for j in i..vec.len() {
// do something with vec[i] and vec[j]
}
}

Your suggested code:
for x in vec.iter()
for y in x.next()
wouldn't work even if it were syntactically valid because x is not an iterator, it's an element of vec. To get at the iterator, you need to store it in a variable and desugar the for loop into while let:
let mut iter = v.iter();
while let Some(x) = iter {
// ...
}
Now that we have an explicit iter, we can make the inner loop iterate over the remaining items. We can't just iterate over iter because that would exhaust it for the outer loop, but we can clone it to obtain a copy of the outer iterator at its current position:
let mut iter = v.iter();
while let Some(x) = iter {
for y in iter.clone() {
// ...
}
}
Note that we don't need to explicitly call iter.next() before the inner loop, as the first item will have already been spent by the outer loop, and the inner loop will naturally observe only the remaining items of each iteration.
Complete code would look like this:
let v = vec![1, 2, 3];
let mut iter = v.iter();
while let Some(x) = iter.next() {
println!("x = {}", x);
for y in iter.clone() {
println!(" y = {}", y);
}
}
Output:
x = 1
y = 2
y = 3
x = 2
y = 3
x = 3

Related

How to get the current item from iterator

Is it possible to get the current item from an iterator in Rust?
I would like the same functionality as .next() but it wouldn't continue to the next item, it would just return the current item.
so:
fn main() {
let x = vec![1, 2, 3, 4, 5];
let iterator = x.iter(); // Create an iterator
// y is now just a single i32 from the x array
let y = iterator.next().unwrap();
// I'm looking for method that will return the current item from the iterator
// Something like iterator.current() which is not implemented for some reason.
let z = iterator.current();
}
You can wrap your iterator in Peekable:
fn main() {
let x = vec![1, 2, 3, 4, 5];
let iterator = x.iter().peekable();
let y = iterator.next().unwrap();
let z = iterator.peek();
}
peek() returns the about-to-be-yielded item, i.e. the item that will be returned next time you'll call next(). Note that it returns a reference and not an owned item.

How to sum elements of Vec<Vec<f64>> together into a Vec<f64>?

I am looking for an "rusty" way to accumulate a Vec<Vec> into a Vec such that the 1st element of every inner Vec is summed together, every 2nd element of each Vec is summed together, etc..., and the results are collected into a Vec? If I just use sum(), fold(), or accumulate() I believe I will sum entire 1st Vec together into a single element, rather than the 1st element of each inner Vec contained in the 2D Vec.
pub fn main() {
let v1 = vec![1.1, 2.2, 3.3];
let vv = vec![v1; 3];
let desired_result = vec![3.3, 6.6, 9.9];
}
Sometimes it's easy to forget in Rust that the imperative approach exists and is an easy solution.
let mut sums = vec![0.0; vv[0].len()];
for v in vv {
for (i, x) in v.into_iter().enumerate() {
sums[i] += x;
}
}
While I prefer #orlp's solution, if you're hell-bent on doing this the most functionally possible, you could do it like this:
let v1 = vec![1.1, 2.2, 3.3];
let vv = vec![v1; 3];
let sums = vec![0.0; vv[0].len()];
let summed = vv.into_iter().fold(sums, |mut sums, v| {
v.into_iter().enumerate().for_each(|(i, x)| sums[i] += x);
sums
});
Also if knowing beforehand the size of the inner vectors (or taking it from the first occurence in the vv vector), you can use a range iterator:
pub fn main() {
let v1 = vec![1.1, 2.2, 3.3];
let v1_len = v1.len();
let vv = vec![v1; 3];
let res: Vec<f64> = (0..v1_len)
.map(|i| vv.iter().map(|v| v.get(i).unwrap()).sum())
.collect();
println!("{res:?}");
}
Playground

Parallelizing nested loops in rust with rayon

I am trying to parallelize simple nested for loop in Rust with rayon but am unable to:
fn repulsion_force(object: &mut Vec<Node>) {
let v0 = 500.0;
let dx = 0.1;
for i in 0..object.len() {
for j in i + 1..object.len() {
let dir = object[j].position - object[i].position;
let l = dir.length();
let mi = object[i].mass;
let mj = object[j].mass;
let c = (dx / l).powi(13);
let v = dir.normalize() * 3.0 * (v0 / dx) * c;
object[i].current_acceleration -= v / mi;
object[j].current_acceleration += v / mj;
}
}
}
Tried to follow this post and created this:
use rayon::prelude::*;
object.par_iter_mut()
.enumerate()
.zip(object.par_iter_mut().enumerate())
.for_each(|((i, a), (j, b))| {
if j > i {
// code here
}
});
cannot borrow *object as mutable more than once at a time
second mutable borrow occurs here
But it didn't work. My problem is a bit different than one in the post because I modify two elements in one iteration and trying to borrow them both as mutable which Rust does not like, while I don't like idea of doing double the calculations when its not necessary.
Another try was to iterate through Range:
use rayon::prelude::*;
let length = object.len();
(0..length).par_bridge().for_each(|i| {
(i+1..length).for_each(|j| {
let dir = object[j].position - object[i].position;
let l = dir.length();
let mi = object[i].mass;
let mj = object[j].mass;
let c = (dx / l).powi(13);
let v = dir.normalize() * 3.0 * (v0 / dx) * c;
object[i].current_acceleration -= v / mi;
object[j].current_acceleration += v / mj;
});
cannot borrow object as mutable, as it is a captured variable in a Fn closure
This one I honestly don't understand at all, and E0596 isn't much help - my object is a &mut. New to Rust and would appreciate any help!
What you're trying to do is not as trivial as you might imagine :D
But let's give it a shot!
First, let's make a minimal reproducible example, - this is the common way to ask questions on stackoverflow. As you can imagine, we don't know what your code should do. Nor do we have the time to try and figure it out.
We would like to get a simple code piece, which fully describes the problem, copy-paste it, run it and derive a solution.
So here's my minimal example:
#[derive(Debug)]
pub struct Node {
value: i32,
other_value: i32,
}
fn repulsion_force(object: &mut [Node]) {
for i in 0..object.len() {
for j in i + 1..object.len() {
let mi = 2 * object[i].value;
let mj = mi + object[j].value;
object[i].other_value -= mi;
object[j].other_value += mj;
}
}
}
Firstly i've created a simple node type. Secondly, i've simplified the operations.
Note that instead of passing a vector, i'm passing a mutable slice. This form retains more flexibility, in case I migth need to pass a slice form an array for exmaple. Since you're not using push(), there's no need to reference a vector.
So next let's reformulate the problem for parallel computation.
First consider the structure of your loops and access pattern.
Your're iterating over all the elements in the slice, but for each i iteration, you're only modifying the object at [i] and [j > i].
so let's split the slice according to that pattern
fn repulsion_force(object: &mut [Node]) {
for i in 0..object.len() {
let (left, right) = object.split_at_mut(i + 1);
let mut node_i = &mut left[i];
right.iter_mut().for_each(|node_j| {
let mi = 2 * node_i.value;
let mj = mi + node_j.value;
node_i.other_value -= mi;
node_j.other_value += mj;
});
}
}
By splitting the slice we are getting two slices. The left slice contains [i],
the right slice contains [j > i]. next we rely on an iterator instead of indices for the iteration.
The next step would be to make the internal loop parallel. However, the internal loop modifies node_i at each iteration. That means more than one thread might try to write to node_i at the same time, causing a data race. As such the compiler won't allow it. The solution is to include a synchronization mechanism.
For a general type, that might be a mutex. But since you're using standard mathematical operations i've opted for an atomic, as these are usually faster.
So we modifiy the Node type and the internal loop to
#[derive(Debug)]
pub struct Node {
value: i32,
other_value: AtomicI32,
}
fn repulsion_force(object: &mut [Node]) {
for i in 0..object.len() {
let (left, right) = object.split_at_mut(i + 1);
let mut node_i = &mut left[i];
right.iter_mut().par_bridge().for_each(|node_j| {
let mi = 2 * node_i.value;
let mj = mi + node_j.value;
node_i.other_value.fetch_sub(mi, Relaxed);
node_j.other_value.fetch_add(mj, Relaxed);
});
}
}
you can test the code with the snippet
fn main() {
// some arbitrary object vector
let mut object: Vec<Node> = (0..100).map(|k| Node { value: k, other_value: AtomicI32::new(k) }).collect();
repulsion_force(&mut object);
println!("{:?}", object);
}
Hope this help! ;)

Retrieve the state in scan() iterator?

To obtain the partial sums of a sequence of integers, I can use scan() on the iterator like this:
let partial: Box<[u32]> =
list
.iter()
.scan(0, |st, elem| {
let ret = *st;
*st += elem;
Some(ret)
})
.collect();
The above code works well, but I'm trying to modify it to give me the total sum as well.
Something like:
let (partial, total): (Box<[u32]>, u32) =
list
.iter()
.scan(0, |st, elem| {
// TODO
})
.collect();
It seems like I would just need to obtain the eventual value of st, and the iterator should already know it's value. However, I can't seem to find a way to retrieve that value, short of doing a second iteration over the whole sequence (e.g. with fold()).
Is there a way to find the partial sums and the total sum in a single pass?
Include the total sum in the scan, but then split off the last value.
use std::iter;
fn main() {
let list = vec![1, 2, 3, 4];
// Add zero at the start to emulate what you had before
let partial: Box<[u32]> = iter::once(0)
.chain(list.iter().scan(0, |st, elem| {
*st += elem;
Some(*st)
}))
.collect();
// unwrap since with the added zero, the slice will always be non-empty
let (total, partial) = partial.split_last().unwrap();
println!("partial sums: {:?}", partial);
println!("total sum: {}", total);
}
(playground)
Or using successors():
fn main() {
use std::iter::successors;
let list = vec![1, 2, 3, 4];
let mut iter = list.iter();
let partial: Vec<_> = successors(Some(0), |n| iter.next().map(|i| n + i)).collect();
// unwrap since with the added zero, the slice will always be non-empty
let (total, partial) = partial.split_last().unwrap();
assert_eq!(partial, &[0, 1, 3, 6]);
assert_eq!(total, &10);
}
(playground)
You must decide what you want to do in the closure.
As it stands in your code, you remember ret = *st which is the accumulator's value before the addition takes place, and you return Some(ret). Thus, the first item you get in the result is currently 0.
If you want the value after the sums, you should just return Some(*st), which is the updated accumulator's value after the addition.

How can I introduce a copied variable as mutable in a if-let statement?

I have a HashMap<i8, i8> which could contain cycles:
let mut x: HashMap<i8, i8> = HashMap::new();
x.insert(1, 6);
x.insert(3, 5);
x.insert(5, 1);
To get the final value for 3, it should first lookup x[3], then x[5] and finally x[1] which should yield 6. I decided to use a while let loop:
let mut y = x[&3]; // y: i8
while let Some(&z) = x.get(&y) {
y = z;
}
println!("{}", y);
x.insert(0, 0);
This works fine, but it would panic! if 3 is not in the map. As I don't want to do anything about the None case, I want to use a if let (similar to the while let used).
I have tried some notations:
if let Some(&y) = x.get(&3): copies the value, but y is immutable (y: i8)
if let Some(mut y) = x.get(&3): y is mutable, but the value is borrowed (mut y: &i8)
if let mut Some(&y) = x.get(&3): my target: mutable copy, but invalid syntax (mut y: i8)
(All variants are available at Rust Playground, but you need to comment out the third try, as it is invalid syntax)
I would not argue about the second variant, but I need to insert values into my map in the body of the if let. As the map remains borrowed, I can't insert anymore. All I would need is that the value in Some(y) is copied, and y is mutable, so that the borrow checker is satisfied and I can do my recursive lookups.
Your approach #1 is a perfectly correct match, you just need to make the y variable mutable. One possibility is to convert Option<&i8> to Option<i8>, enabling the use of mut y in the pattern. For example, Option::map can dereference the value:
if let Some(mut y) = x.get(&3).map(|ref| *ref) {
Since Copy implies (cheap) Clone, you can express the same using Option::cloned():
if let Some(mut y) = x.get(&3).cloned() {
As of Rust 1.35, you can use Option::copied(), which is only defined for Copy types and just copies the value:
if let Some(mut y) = x.get(&3).copied() {
Another possibility is to leave your approach #1 as-is, but correct it simply by introducing a separate mutable variable inside the if let block:
if let Some(&y) = x.get(&3) {
let mut y = y;
...
Your code basically works:
use std::collections::HashMap;
fn main() {
let mut x: HashMap<i8, i8> = HashMap::new();
x.insert(1, 6);
x.insert(3, 5);
x.insert(5, 1);
let mut key = 3;
while let Some(&z) = x.get(&key) {
key = z;
}
println!("{}", key);
x.insert(key, 0);
}
Here, key is left as the last key that did not match.

Resources