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
Related
I'd like to split and collect this strangely-shaped vector
let v = vec![
0, 1, 2, 3,
4, 5, 6, 7,
8, 9,
10, 11,
12, 13,
];
into these two matrices:
let v1 = vec![
vec![0, 1, 2, 3],
vec![4, 5, 6, 7],
];
let v2 = vec![
vec![8, 9],
vec![10, 11],
vec![12, 13],
];
(The elements are sequential (i.e. 1, 2, 3, ...) but this is just for example. Also, though the number of matrices are two here, this number is just for example; sometimes it should be three or more.)
Trivially it is possible (Rust Playground):
let mut v1: Vec<Vec<usize>> = vec![];
for i in 0..2 {
v1.push(v.iter().skip(i * 4).take(4).copied().collect());
}
let mut v2: Vec<Vec<usize>> = vec![];
for i in 0..3 {
v2.push(v.iter().skip(8 + i * 2).take(2).copied().collect());
}
But, is there a cleaner way? Here's the pseudo code I want:
let v1 = v.iter().every(4).take(2).collect();
let v2 = v.iter().skip(8).every(2).take(3).collect();
You can split the initial vector into two slices and iterate each of them separately (playground):
let (left, right) = v.split_at(8);
let v1 = left.chunks(4).map(|s| s.to_vec()).collect::<Vec<_>>();
let v2 = right.chunks(2).map(|s| s.to_vec()).collect::<Vec<_>>();
If an external crate is allowed, you can use Itertools::chunks:
v.iter().chunks(4).into_iter().take(2).map(|l| l.copied().collect_vec()).collect()
(Rust Playground)
I have a vector of some elements that I would like to iterate from some index and cycle around from the front again while only visiting each element a single time.
Ex. starting here at index 2,
[0, 1, 2, 3, 4, 5, 6]
^
I would like to have an iterator over the elements [2, 3, 4, 5, 6, 0, 1] (and avoid writing a loop everywhere I need to run through the vector this way).
The standard iteration with cycle() + skip() seemed to be a good start, but it of cause never ends.
Is there any idiomatic way with rusts standard iterators?
You can iterate over the two subslices, and use chain to concatenate them together into a single iterator:
let v = vec![0, 1, 2, 3, 4, 5, 6];
let start_index = 2;
for e in v[start_index..].iter().chain(v[..start_index].iter()) {
println!("{}", e);
}
The obvious fix for your cycle/skip combo is to add a take() to limit it:
fn cycle<T>(slice: &[T], start_pos: usize) -> impl Iterator<Item = &T> {
slice.iter().cycle().skip(start_pos).take(slice.len())
}
Another option is to just chain the two ranges, which even ends up a bit shorter:
fn cycle<T>(slice: &[T], start_pos: usize) -> impl Iterator<Item = &T> {
slice[start_pos..].iter().chain(&slice[..start_pos])
}
Both versions pass test such as:
let v = vec![0, 1, 2, 3, 4, 5, 6];
assert_eq!(cycle(&v, 2).copied().collect::<Vec<_>>(), vec![2, 3, 4, 5, 6, 0, 1]);
This iterator
let data = vec![0, 1, 2, 3, 4, 5];
for x in data.chunks(2) {
println!("{:?}", x);
}
will produce
[0, 1]
[2, 3]
[4, 5]
Can I use iterator to get something like this.
[0, 1]
[1, 2]
[2, 3]
[3, 4]
[4, 5]
I know how to do that using for loop. But can iterator do this better?
I guess your can use Itertools.tuple_windows for this. According to the documentation it "returns an iterator over all contiguous windows producing tuples of a specific size (up to 4)" :
use itertools::Itertools;
use itertools::TupleWindows;
use std::slice::Iter;
let data = vec![0, 1, 2, 3, 4, 5];
let it: TupleWindows<Iter<'_, i32>, (&i32, &i32)> = data.iter().tuple_windows();
for elem in it {
println!("{:?}", elem);
}
Output:
(0, 1)
(1, 2)
(2, 3)
(3, 4)
(4, 5)
Edit:
As noted in comment1 by #Masklinn and comment2 by #SebastianRedl, you can also use windows from stdlib and avoid including Itertools in your project. But note that it only works for slices (or things that coerce to slices), not general iterators (which is fine in your case).
let data = vec![0, 1, 2, 3, 4, 5];
let it = data.windows(2);
for elem in it {
println!("{:?}", elem);
}
Output:
[0, 1]
[1, 2]
[2, 3]
[3, 4]
[4, 5]
Alternatively, without extra dependencies, you can zip the same iterator, skip one item on the second one.
fn main() {
let data = vec![0, 1, 2, 3, 4, 5];
let i1 = data.iter();
let i2 = data.iter();
for (a, b) in i1.zip(i2.skip(1)) {
println!("{} {}", a, b);
}
}
Playground
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)
I have a slice of bytes start = [30u8; 5] and middle = [40u8; 3] and a vector of byte slices:
let first = [1u8; 10];
let second = [2u8; 10];
let third = [3u8; 10];
let elements: Vec<[u8; 10]> = vec![first, second, third];
I want to concatenate everything together, in such a way that I will obtain a single byte slice which looks as
[30, 30, 30, 30, 30, 40, 40, 40, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3]
However, although I can concatenate start and middle when I try to append the vector elements it fails. I know that I am wrongly trying to iterate through the elements of the vector to concatenate, but I can't figure out how to do it correctly?
fn main() {
let start = [30u8; 5];
let middle = [40u8; 4];
let first = [1u8; 10];
let second = [2u8; 10];
let third = [3u8; 10];
let elements: Vec<[u8; 10]> = vec![first, second, third];
println!("{:?}", elements.iter());
for key in elements.iter() {
println!("{:?}", key.iter());
}
let alltogether: Vec<u8> = start
.iter()
.cloned()
.chain(middle.iter().cloned())
.chain(elements.iter().iter().cloned())
.collect();
println!("{:?}", alltogether);
}
This example can be copy-pasted into the Rust playground.
You possibly want this:
let alltogether: Vec<u8> = start
.iter()
.cloned()
.chain(middle.iter().cloned())
.chain(elements.iter().flatten().cloned())
.collect();
Note that there is also copied (instead of cloned) that can be used for Copyable types.
If the stuff in elements does not implement IntoIterator itself, you can use flat_map to specify how to convert one element to an iterator.