How can I reduce an Iterator of booleans using the && operator? Here is an example (just the relevant part):
let row: Vec<(u32, bool)> = vec![(12, true), (13, false), (15, true)];
row.iter()
.map(|it| {
let (_, marked) = it;
marked
})
.reduce(|acc, mk | acc && mk);
The compiler recommends dereferencing acc first, then dereferencing mk, and finally borrowing the whole expression. It's a quite simple operation but I'm unable to find the Rustacean way to do it.
Here's an alternative solution that uses fold to specify an initial value:
let val: bool = row.iter()
.map(|it| {
let (_, marked) = it;
marked
})
.fold(true, |acc, mk| acc && *mk);
The reason acc && mk doesn't work is because you have an iterator over &bool but you want a bool. *acc && *mk doesn't work because the accumulator is of type bool, so you want acc && *mk. However, you can no longer use reduce since the accumulator and values aren't the same type (bool vs &bool), hence the need for fold.
Also note that fold and map can be combined:
let val: bool = row.iter()
.fold(true, |acc, (_, mk)| acc && *mk);
Because There are three common methods which can create iterators from a collection;
iter(), which iterates over &T.
iter_mut(), which iterates over &mut T.
into_iter(), which iterates over T.
Your code uses iter (), so the iteration is & type, so you need to use & to extract value
Maybe you can do it like this:
let row: Vec<(u32, bool)> = vec![(12, true), (13, false), (15, true)];
let op = row.iter()
.map(|&it| {
let (_, marked) = it;
marked // No dereference is required
})
.reduce(|acc, mk| acc && mk);
println!("{:?}",op);
or
let row: Vec<(u32, bool)> = vec![(12, true), (13, false), (15, true)];
let op = row.into_iter()
.map(|it| {
let (_, marked) = it;
marked // No dereference is required
})
.reduce(|acc, mk| acc && mk);
println!("{:?}",op);
I think the cleanest is below. Using this reference pattern; you can also destructure
the tuple inline, whereas fold is a bit like reduce, except that you won't get constrained to Option<Self::Item> as return type, and have to provide an initial value, etc.
let result = row
.iter()
.map(|(_, marked)| marked)
.fold(true, |acc, &mk| acc && mk);
result will be of type bool.
After trying things the best solution I found is dereferencing value returned in previous map, so instead of returning a reference to boolean returns an owned copy. Here is the modified question code:
let row: Vec<(u32, bool)> = vec![(12, true), (13, false), (15, true)];
row.iter()
.map(|it| {
let (_, marked) = it;
*marked // Dereference here
})
.reduce(|acc, mk | acc && mk);
Related
I have a Vec<f64> and I am trying to get say every 7th element of the vector till I run out of bounds, into another Vec<f64>. I thought maybe I could create an index of the elements I want and then filter based on that. But I can't seem to be able to do this directly or indirectly. What I tried
let x: Vec<f64> = (1..200)
.map(|x| (x as f64)/(200 as f64))
.collect();
let y: Vec<f64> = x
.enumerate()
.filter(|&(i, _)| i % 7 == 0 )
.map(|(_, e)| e)
.collect();
But this did not work with compile error enumerate method cannot be called on Vec<f64> due to unsatisfied trait bounds. I also found a retain method but don't see a way to apply it on the index rather than the element. A robust search of SO surprisingly did not yield anything.
Note that there is a specialized iterator adapter for that, step_by():
let y: Vec<_> = x.into_iter().step_by(7).collect();
I also found a retain method but don't see a way to apply it on the index rather than the element.
While Vec::retain does not give you any sort of index, it takes an FnMut and is documented to operate in-order:
This method operates in place, visiting each element exactly once in the original order, and preserves the order of the retained elements.
So you can just keep track of the index yourself:
let mut idx = 0;
x.retain(|_| {
let v = idx;
idx += 1;
v % 2 == 0
});
Or here you can specialise with a simple toggle:
let mut keep = false;
x.retain(|_| {
keep = !keep;
keep
});
Thanks for the comments, patching everything together into a more complete answer for the community. Let's say this is the Vec: let x: Vec<f64> = (1..10).map(|x| (x as f64)/(10 as f64)).collect();
To filter the vector based on index, first we create an iterator with into_iter, then enumerate it to get index, then apply the filter, and then a map to remove the index, finally collecting it to f64 vector.
let y: Vec<f64> = x
.into_iter()
.enumerate()
.filter(|&(i, _)| i % 2 == 0 )
.map(|(_, e)| e)
.collect();
If the scope of y is shorter than that of x, and if you had large values in y (say string), it might be preferable to make y a vector of references rather than values.
let y: Vec<&f64> = x
.iter()
.enumerate()
.filter(|&(i, _)| i % 2 == 0 )
.map(|(_, e)| e)
.collect();
The key difference here is using iter() instead of iter_into(). This page in rust book explains it:
The iter method produces an iterator over immutable references. If we
want to create an iterator that takes ownership of v1 and returns
owned values, we can call into_iter instead of iter. Similarly, if we
want to iterate over mutable references, we can call iter_mut instead
of iter.
Now, for this specific question, applying a filter to the index is probably not needed. A simpler way, as noted by Chayim below is
let y: Vec<_> = x.into_iter().step_by(2).collect();
I want to change the value of a specific attribute of a vector of objects.
my code and logic are as follows:
let mut person_found: Vec<Person> = persons.clone().into_iter().filter(|x| x.id == "3")
.map(|x| x.name = "Carlos".to_string()).collect();
println!("original: {:?}", &persons);
println!("modified person: {:?}", &person_found);
But it gives me the following error and I can't understand it well.
error[E0277]: a value of type `Vec<Person>` cannot be built from an iterator over elements of type `()`
--> src\main.rs:17:45
|
17 | .map(|x| x.name = "Carlos".to_string()).collect();
| ^^^^^^^ value of type `Vec<Person>` cannot be built from `std::iter::Iterator<Item=()>`
|
= help: the trait `FromIterator<()>` is not implemented for `Vec<Person>`
The result of an assignment is () (the unit value). So if you do y = (x = 123); then x is assigned 123 and y is assigned ().
The Rust Reference has a short sentence stating:
An assignment expression always produces the unit value.
– Assignment expressions - Operator expressions - The Rust Reference
You need to change so it explicitly returns x on the next line, for that to work. If you want to mutate x then you also need to change |x| to |mut x|.
let person_found: Vec<Person> = persons
.clone()
.into_iter()
.filter(|x| x.id == "3")
.map(|mut x| {
x.name = "Carlos".to_string();
x
})
.collect();
Alternatively, instead of cloning the whole persons Vec upfront, I'd instead use cloned() after filter() or clone() in map(), i.e. only when needed.
let person_found: Vec<Person> = persons
.iter()
.filter(|x| x.id == "3")
.cloned()
.map(|mut x| {
x.name = "Carlos".to_string();
x
})
.collect();
You are returning nothing in your map expr line. You can handle with filter_map though:
let mut person_found: Vec<Person> = persons
.iter()
.filter_map(|p|
(p.id == 3).then_some(Person {
name: String::from("Carlos"),
..p.clone()}))
.collect();
Playground
Both of the following work (in 2 invocations), but they feel too verbose.
fn main() {
let v = vec![Some(0), Some(1), None, Some(2)];
assert_eq!(
vec![0,2,4],
v.iter()
.filter(|x| x.is_some())
.map(|x| x.unwrap() * 2)
.collect::<Vec<u8>>());
assert_eq!(
vec![0,2,4],
v.iter()
.filter_map(|x| *x)
.map(|x| x*2)
.collect::<Vec<u8>>());
}
filter_map is close to what I want:
[filter_map] removes the Option layer automatically. If your
mapping is already returning an Option and you want to skip over
Nones, then filter_map is much, much nicer to use.
doc.rust-lang.org
But it doesn't unwrap the value in the closure because it expects an Option to be returned.
Is there a way to both filter on only the Some values, and map over those values with a single invocation?
Such as:
// Fake, does not work
fn main() {
let v = vec![Some(0), Some(1), None, Some(2)];
assert_eq!(
vec![0,2,4],
v.iter()
.map_only_some(|x| x * 2)
.collect::<Vec<u8>>());
}
Well I figured it out, and Iterator's next always returns an Option, so you just have to flatten it:
// Since v.iter().next() is Some(Some(0)), the following works
assert_eq!(
vec![0,2,4],
v.iter()
.flatten()
.map(|x| x * 2)
.collect::<Vec<u8>>());
It's not in a single invocation, but it's much much cleaner and, I think, idiomatic.
Is there a way to both filter on only the Some values, and map over those values with a single invocation?
You already use it filter_map():
fn main() {
let v = vec![Some(0), Some(1), None, Some(2)];
assert_eq!(
vec![0, 2, 4],
v.iter()
.filter_map(|x| x.map(|x| x * 2))
.collect::<Vec<u8>>()
);
}
For example, given the data:
2 : 4
1 : 3
5 : 2
The function would return 2 since its value (4) is the highest.
I am doing:
let mut max_val = 0;
let mut max_key = "";
for (k, v) in a_hash_map.iter() {
if *v > max_val {
max_key = k;
max_val = *v;
}
}
Is there a nicer or quicker or simpler way to do this?
Iterate through all the key-value pairs in the hashmap, comparing them by the values, keeping only the key of the maximum:
use std::collections::HashMap;
fn example<K, V>(a_hash_map: &HashMap<K, V>) -> Option<&K>
where
V: Ord,
{
a_hash_map
.iter()
.max_by(|a, b| a.1.cmp(&b.1))
.map(|(k, _v)| k)
}
fn main() {
let map: HashMap<_, _> = vec![(2, 4), (1, 3), (5, 2)].into_iter().collect();
dbg!(example(&map));
}
See also:
How do I create a map from a list in a functional way?
How can min_by_key or max_by_key be used with references to a value created during iteration?
let key_with_max_value = a_hashmap.iter().max_by_key(|entry | entry.1).unwrap();
dbg!(key_with_max_value.0);
You will need to do better error handling. This code just does an unwrap, expecting that there would be at least one element.
perhaps you can have a try with this: if let Some(max) = a_hash_map.keys().max(){println!("max:{}", max);}
I would like to use the Scan iterator to construct a vector in a declarative fashion. It is clear how to achieve this by copying the intermediate state. The following expression compiles and produced the desired series:
let vec = (0..10).scan(0, |state, current| {
*state = *state + current;
Some(*state)
}).collect::<Vec<_>>();
However, if I try to achieve the same behavior by moving the state instead of copying it, I get in trouble with lifetimes. For example, when working with vectors instead of integers, one cannot move the state out of the closure and reuse it in the next iteration. The expression
let vec = (0..10).map(|x| vec![x]).scan(vec![0], |state, current| {
*state = vec![state[0] + current[0]];
Some(*state)
}).collect::<Vec<_>>();
fails to compile due to
error: cannot move out of borrowed content [E0507]
Some(*state)
^~~~~~
see for example this MVCE.
Borrowing the state instead of moving would also be an option:
let start = &vec![0];
let vec = (0..10).map(|x| vec![x]).scan(start, |state, current| {
*state = &vec![state[0] + current[0]];
Some(*state)
}).collect::<Vec<_>>();
but this fails because the new value falls out of scope when the state is returned.
error: borrowed value does not live long enough
*state = &vec![state[0] + current[0]]
What I ended up doing is using the for loop
let xs = &mut Vec::<Vec<i32>>::with_capacity(10);
xs.push[vec!(0)];
for x in 1..10 {
let z = vec![xs.last().unwrap()[0] + x];
xs.push(z);
};
but I wold prefer a chaining solution.
Let's check the definition of scan:
fn scan<St, B, F>(self, initial_state: St, f: F) -> Scan<Self, St, F>
where F: FnMut(&mut St, Self::Item) -> Option<B>
Note that B is distinct from St. The idea of scan is that:
you keep an accumulator of type St
at each iteration, you produce a value of type B
and indeed it is not quite suited to returning values of type St because you are only borrowing St and do not control its lifetime.
scan is made for you to return a brand new value each time:
let xs = (0..10).scan(0, |state, current| {
*state += current;
Some(NonCopy::new(*state))
}).collect::<Vec<_>>();
and that's it!
A note on efficiency.
The state of scan is a sunk cost so it is best to use a cheap state (a single integer here).
If you need a larger type X and wish to "get your memory back", then you can pass an &mut Option<X> and then use .take() after the scan:
let mut x = Some(NonCopy::new(0));
let xs = (0..10).scan(&mut x, |state, current| {
let i: &mut i32 = &mut state.as_mut().unwrap().value;
*i += current;
Some(NonCopy::new(*i))
}).collect::<Vec<_>>();
let _ = x.take();
It's not as elegant, of course.
I don't think it is possible to do it without cloning value using scan method.
When you return a non-Copy value from the closure, you lose ownership of that value. And it's not possible to keep any reference to it, because it's new owner could move the value in memory anywhere it wants (for example, during vector resizing), and Rust is intended to protect against this kind of errors.
By chaining solution, do you mean this?
let vec = (0..10)
.fold((Vec::with_capacity(10), 0), |(mut vec, previous), x| {
vec.push(vec![previous + x]);
(vec, previous + x)
})
.0;