How to zip Vec<T> with indexed position - rust

Following my question, How to iterate a Vec with indexed position in Rust, now I need to zip two dynamic vectors with their indexed position.

The enumerate function exists for all iterators. Using zip on two iterators a and b yields another iterator. Therefor you can also call enumerate on the resulting iterator.
fn main() {
let a = vec![1; 10];
let b = vec![2; 10];
let it = a.iter().zip(b.iter());
for (i, (x, y)) in it.enumerate() {
println!("{}: ({}, {})", i, x, y);
}
}

fn main() {
let a = vec![1; 10];
let b = vec![2; 10];
for ((i,x),(j,y)) in a.iter().enumerate().zip(b.iter().enumerate()) {
println!("(({},{}),({},{}))", i, x, j, y);
}
}

Related

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

How to get the index of the current element being processed in the iteration without a for loop?

I have read How to iterate a Vec<T> with the indexed position? where the answer is to use enumerate in a for-loop.
But if I don't use a for-loop like this:
fn main() {
let v = vec![1; 10]
.iter()
.map(|&x| x + 1 /* + index */ ) // <--
.collect::<Vec<_>>();
print!("v{:?}", v);
}
How could I get the index in the above closure?
You can also use enumerate!
let v = vec![1; 10]
.iter()
.enumerate()
.map(|(i, &x)| x + i)
.collect::<Vec<_>>();
println!("v{:?}", v); // prints v[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
Let's see how this works. Iterator::enumerate returns Enumerate<Self>. That type also implements Iterator:
impl<I> Iterator for Enumerate<I>
where
I: Iterator,
{
type Item = (usize, <I as Iterator>::Item);
// ...
}
As you can see, the new iterator yields tuples of the index and the original
value.
You can simply use enumerate:
fn main() {
let v = vec![1; 10]
.iter()
.enumerate()
.map(|(i, x)| i + x)
.collect::<Vec<_>>();
print!("v{:?}", v);
}
The reason for this is because the for loop takes an enumerator:
In slightly more abstract terms:
for var in expression {
code
}
The expression is an iterator.

How does one get an iterator to the max value element in Rust?

I want to access the element next to the maximal one in a Vec<i32>. I'm looking for something like this:
let v = vec![1, 3, 2];
let it = v.iter().max_element();
assert_eq!(Some(&2), it.next());
In C++, I would go with std::max_element and then just increase the iterator (with or without bounds checking, depending on how adventurous I feel at the moment). The Rust max only returns a reference to the element, which is not good enough for my use case.
The only solution I came up with is using enumerate to get the index of the item - but this seems manual and cumbersome when compared to the C++ way.
I would prefer something in the standard library.
This example is simplified - I actually want to attach to the highest value and then from that point loop over the whole container (possibly with cycle() or something similar).
C++ iterators are not the same as Rust iterators. Rust iterators are forward-only and can only be traversed once. C++ iterators can be thought of as cursors. See What are the main differences between a Rust Iterator and C++ Iterator? for more details.
In order to accomplish your goal in the most generic way possible, you have to walk through the entire iterator to find the maximum value. Along the way, you have to duplicate the iterator each time you find a new maximum value. At the end, you can return the iterator corresponding to the point after the maximum value.
trait MaxElement {
type Iter;
fn max_element(self) -> Self::Iter;
}
impl<I> MaxElement for I
where
I: Iterator + Clone,
I::Item: PartialOrd,
{
type Iter = Self;
fn max_element(mut self) -> Self::Iter {
let mut max_iter = self.clone();
let mut max_val = None;
while let Some(val) = self.next() {
if max_val.as_ref().map_or(true, |m| &val > m) {
max_iter = self.clone();
max_val = Some(val);
}
}
max_iter
}
}
fn main() {
let v = vec![1, 3, 2];
let mut it = v.iter().max_element();
assert_eq!(Some(&2), it.next());
}
See also:
How can I add new methods to Iterator?
I actually want to attach to the highest value and then from that point loop over the whole container (possibly with cycle() or something similar).
In that case, I'd attempt to be more obvious:
fn index_of_max(values: &[i32]) -> Option<usize> {
values
.iter()
.enumerate()
.max_by_key(|(_idx, &val)| val)
.map(|(idx, _val)| idx)
}
fn main() {
let v = vec![1, 3, 2];
let idx = index_of_max(&v).unwrap_or(0);
let (a, b) = v.split_at(idx);
let mut it = b.iter().chain(a).skip(1);
assert_eq!(Some(&2), it.next());
}
See also:
What's the fastest way of finding the index of the maximum value in an array?
Using max_by_key on a vector of floats
What is the idiomatic way to get the index of a maximum or minimum floating point value in a slice or Vec in Rust?
Find the item in an array with the largest property
a simple solution is to use fold,
the following code produces "largest num is: 99"
let vv:Vec<i32> = (1..100).collect();
let largest = vv.iter().fold(std::i32::MIN, |a,b| a.max(*b));
println!("largest {} ", largest);
If all you want is the value of the item following the maximum, I would do it with a simple call to fold, keeping track of the max found so far and the corresponding next value:
fn main() {
let v = vec![1, 3, 2];
let nxt = v.iter().fold (
(None, None),
|acc, x| {
match acc {
(Some (max), _) if x > max => (Some (x), None),
(Some (max), None) => (Some (max), Some (x)),
(None, _) => (Some (x), None),
_ => acc
}
}
).1;
assert_eq!(Some(&2), nxt);
}
playground
Depending on what you want to do with the items following the max, a similar approach may allow you to do it in a single pass.

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.

How to use a map over vectors?

Although vectors are best suited for procedural programming, I would like to use a map function on them. The following snippet works:
fn map<A, B>(u: &Vec<A>, f: &Fn(&A) -> B) -> Vec<B> {
let mut res: Vec<B> = Vec::with_capacity(u.len());
for x in u.iter() {
res.push(f(x));
}
res
}
fn f(x: &i32) -> i32 {
*x + 1
}
fn main() {
let u = vec![1, 2, 3];
let v = map(&u, &f);
println!("{} {} {}", v[0], v[1], v[2]);
}
Why isn't there any such function in the standard library (and also in std::collections::LinkedList)? Is there another way to deal with it?
Rust likes to be more general than that; mapping is done over iterators, rather than over solely vectors or slices.
A couple of demonstrations:
let u = vec![1, 2, 3];
let v: Vec<_> = u.iter().map(f).collect();
let u = vec![1, 2, 3];
let v = u.iter().map(|&x| x + 1).collect::<Vec<_>>();
.collect() is probably the most magic part of it, and allows you to collect all the elements of the iterator into a large variety of different types, as shown by the implementors of FromIterator. For example, an iterator of Ts can be collected to Vec<T>, of chars can be collected to a String, of (K, V) pairs to a HashMap<K, V>, and so forth.
This way of working with iterators also means that you often won’t even need to create intermediate vectors where in other languages or with other techniques you would; this is more efficient and typically just as natural.
As pointed out by bluss, you can also use the mutable iterator to mutate the value in place, without changing the type:
let mut nums = nums;
for num in &mut nums { *num += 1 }
println!("{:p} - {:?}", &nums, nums);
The function Vec::map_in_place was deprecated in Rust 1.3 and is no longer present in Rust 1.4.
Chris Morgan's answer is the best solution 99% of the time. However, there is a specialized function called Vec::map_in_place. This has the benefit of not requiring any additional memory allocations, but it requires that the input and output type are the same size (thanks Levans) and is currently unstable:
fn map_in_place<U, F>(self, f: F) -> Vec<U>
where F: FnMut(T) -> U
An example:
#![feature(collections)]
fn main() {
let nums = vec![1,2,3];
println!("{:p} - {:?}", &nums, nums);
let nums = nums.map_in_place(|v| v + 1);
println!("{:p} - {:?}", &nums, nums);
}

Resources