The rust standard library has a fold() which collapses an iterator into a single result:
let a = [1, 2, 3];
// the sum of all of the elements of the array
let sum = a.iter().fold(0, |acc, x| acc + x);
assert_eq!(sum, 6);
Does the standard library have an equivalent version that yields each element? That is, something like:
let partial_sums = a.iter()
.what_goes_here(0, |acc, x| acc + x)
.collect::<Vec<_>>();
assert_eq!(partial_sums, vec![1, 3, 6]);
Effectively, iter.fold(init, f) is semantically equivalent to
iter
.what_goes_here(init, f)
.last()
.unwrap_or(init)
For anyone in the same boat as me, I'm looking for the Rust equivalent of the C++ algorithm partial_sum.
You want Iterator::scan:
fn main() {
let v = vec![1, 2, 3];
let res = v
.iter()
.scan(0, |acc, &x| {
*acc += x;
Some(*acc)
})
.collect::<Vec<_>>();
assert_eq!(res, vec![1, 3, 6]);
}
Related
I have a vector containing two vectors of different sizes:
let vectors = vec![
vec![0, 1],
vec![2, 3, 4]
];
I would like to create an iterator to cycle over the elements of each vector, returning:
0: [0, 2]
1: [1, 3]
2: [0, 4]
3: [1, 2]
...
In this example there are two vectors, but I would like to generalize this for k vectors.
I have tried this:
let cycles = vectors
.into_iter()
.map(|x| x.into_iter().cycle());
loop {
let output: Vec<_> = cycles
.map(|x| x.next().unwrap())
.collect();
}
However, it does not work, because x cannot be borrowed as mutable.
error[E0596]: cannot borrow `x` as mutable, as it is not declared as mutable
--> src/main.rs:14:22
|
14 | .map(|x| x.next().unwrap())
| - ^^^^^^^^ cannot borrow as mutable
| |
| help: consider changing this to be mutable: `mut x`
I understand the error, but I fail to think of an alternative way to build this iterator. Playground.
You have to collect the iterators into some datastructure like Vec.
You can then use iter_mut to iterate over mutable references which let you advance the collected iterators.
fn main() {
let vectors = vec![vec![0, 1], vec![2, 3, 4]];
let mut cycles = vectors
.into_iter()
.map(|x| x.into_iter().cycle())
.collect::<Vec<_>>();
for i in 0.. {
let output: Vec<_> = cycles.iter_mut().map(|x| x.next().unwrap()).collect();
println!("{i}: {output:?}");
}
}
Do you mean:
0: [0, 2]
1: [1, 3]
2: [0, 4]
3: [1, 2] <- was 3
...
If so:
let vectors: Vec<Vec<u8>> = vec![vec![0, 1], vec![2, 3, 4]];
let mut cycles: Vec<_> = vectors.iter().map(|x| x.iter().cycle()).collect();
for i in 0..4 {
let output: Vec<_> = cycles.iter_mut().map(|x| x.next().unwrap()).collect();
println!("{i}: {output:?}");
}
I have two approaches to grouping characters by the number of occurrences in a string. One of them is using std::collections::HashMap and the second one is using itertools::Itertools::group_by. Unfortunately, grouping with Itertools gives me undesirable results.
Example input word: "Barbara"
Using std::collections::HashMap
let map1 = word.to_lowercase()
.chars()
.fold(HashMap::new(), |mut acc, c| {
*acc.entry(c).or_insert(0) += 1;
acc
});
Result {'a': 3, 'b': 2, 'r': 2}
And using itertools::Itertools::group_by
let map2: HashMap<char, u32> = word.to_lowercase()
.chars()
.group_by(|&x| x)
.into_iter()
.map(|(k, v)| (k, v.count() as u32))
.collect();
Result {'r': 1, 'a': 1, 'b': 1}
Oddly enough, when the input string has identical characters in succession, Itertools takes those characters into account.
The question is, what makes it return different results?
Playground
You're looking for into_group_map_by. group_by only groups consecutive elements according to the docs.
use itertools::Itertools;
use std::collections::HashMap;
fn main() {
let word = "Barbara";
let map1 = word
.to_lowercase()
.chars()
.fold(HashMap::new(), |mut acc, c| {
*acc.entry(c).or_insert(0) += 1;
acc
});
println!("{:?}", map1);
let map2: HashMap<char, u32> = word
.to_lowercase()
.chars()
.into_group_map_by(|&x| x)
.into_iter()
.map(|(k, v)| (k, v.len() as u32))
.collect();
println!("{:?}", map2);
}
Output:
{'b': 2, 'a': 3, 'r': 2}
{'b': 2, 'r': 2, 'a': 3}
Playground
There's also into_grouping_map_by, which can be used for this like:
let map2: HashMap<char, u32> = word
.to_lowercase()
.chars()
.into_grouping_map_by(|&x| x)
.fold(0, |acc, _key, _value| acc + 1);
The documentation says (emphasis added):
fn group_by<K, F>(self, key: F) -> GroupBy<K, Self, F>
where
Self: Sized,
F: FnMut(&Self::Item) -> K,
K: PartialEq,
Return an iterable that can group iterator elements. Consecutive elements that map to the same key (“runs”), are assigned to the same group.
It only groups consecutive elements. You'll need to sort the characters before calling group_by.
let map2: HashMap<char, u32> = word.to_lowercase()
.chars()
.sorted()
.group_by(|&x| x)
...
Output:
{'a': 3, 'r': 2, 'b': 2}
{'b': 2, 'a': 3, 'r': 2}
Playground
Say I have an array of primitive integers of length N, and I want to create a new array of the same length by applying a function to each element in the original array. For example, with the swap_bytes method:
let arr: [u64; 4] = [1, 2, 3, 4];
let output: [u64; 4] = [1u64.swap_bytes(), 2u64.swap_bytes(), 3u64.swap_bytes(), 4u64.swap_bytes()];
// Just an example to show the desired output,
// obviously a generic function wouldn't use this code
My question is: would it be faster to make the output array a [MaybeUninit<u64>; 4] to begin with, or would it be just as fast to initialise the output array with zeros ([0u64; 4]), as the element type of the array is a primitive integer?
So basically I'm asking which of these two pieces of code would be faster, and why:
let arr: [u64; 4] = [1, 2, 3, 4];
let mut out = MaybeUninit::uninit_array::<4>();
for i in 0..4 {
out[i] = MaybeUninit::new(arr[i].swap_bytes());
}
MaybeUninit::array_assume_init(out)
or
let arr: [u64; 4] = [1, 2, 3, 4];
let mut out = [0u64; 4];
for i in 0..4 {
out[i] = arr[i].swap_bytes();
}
out
I have a vector and I want to sort it, where the first criterion is frequency. Second criterion is position in the vector. If two elements have the same number of occurrences, I want the most recently seen element to take advantage and go first. In the end, I want to remove duplicate elements from it.
For instance, if the input is this:
fn main() {
let history = vec![3, 2, 4, 6, 2, 4, 3, 3, 4, 5, 6, 3, 2, 4, 5, 5, 3];
}
The output should be:
3 4 5 2 6
How can I do this in Rust?
A straightforward method is to build hash maps for frequencies and positions of the elements:
use std::collections::HashMap;
fn frequency_map(nums: &[i32]) -> HashMap<i32, usize> {
let mut map = HashMap::new();
for &n in nums {
*map.entry(n).or_insert(0) += 1;
}
map
}
fn position_map(nums: &[i32]) -> HashMap<i32, usize> {
let mut map = HashMap::new();
for (pos, &n) in nums.iter().enumerate() {
map.insert(n, pos);
}
map
}
And then do an unstable sort by position followed by a stable sort by frequency:
fn custom_sort(nums: &mut Vec<i32>) {
let freq_map = frequency_map(nums);
let pos_map = position_map(nums);
nums.sort_unstable_by(|a, b| pos_map.get(b).unwrap().cmp(pos_map.get(a).unwrap()));
nums.dedup();
nums.sort_by(|a, b| freq_map.get(b).unwrap().cmp(freq_map.get(a).unwrap()));
}
Example:
use itertools::Itertools;
fn main() {
let mut history = vec![3, 2, 4, 6, 2, 4, 3, 3, 4, 5, 6, 3, 2, 4, 5, 5, 3];
custom_sort(&mut history);
println!("[{}]", history.iter().format(", "));
}
Output:
[3, 4, 5, 2, 6]
(playground)
How do I make to work the following code:
let arr: [u8; 3] = [1, 2, 3];
let x1: &[u8] = &arr[0..];
let x2: &[u8] = &arr[1..];
let d: isize = x2 - x1;
I have two slices into one vector and I want to know the difference between their start pointers (should be 1 in that example).
One of approaches is to convert pointers to slice contents to isize and do arithmetics on these values:
let arr: [u8; 3] = [1, 2, 3];
let x1: &[u8] = &arr[0..];
let x2: &[u8] = &arr[1..];
let d: isize = x2.as_ptr() as isize - x1.as_ptr() as isize;
println!("{}", d);
But I'm not sure how this would work if the address does not fit into isize.