Minus operation for slices - rust

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.

Related

Cycle over arrays of different sizes using iterators in Rust

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:?}");
}

Performance of initialising integer array from `MaybeUninit<[{integer}; N]>`

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

Sorting a vector based on frequency and position of the elements in Rust

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 to concatenate the individual elements of a vector of slices with other slices?

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.

fold algorithm that yields each partial result

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]);
}

Resources