How to create statically sized array in Rust? - rust

I have the following array of constants in Rust:
const COUNTS: [usize; 5] = [1, 2, 4, 8, 16];
And the point is that I want to iterate over it like this:
for (i, count) in COUNTS.iter().enumerate() {
const length: usize = *count/2;
let indices: [usize; length] = Vec::from_iter(0..length).try_into().unwrap();
let set: IndexSet<usize> = IndexSet::from(indices);
...
}
The point is that from method of IndexSet requires a statically sized array, i.e., [T; N]. What's the proper way here to create a statically sized array that includes the half of the values? Because the above code throws an error at const length: usize = *count/2 that count is a non-constant.

You probably want to use .collect instead, which is a standard way to instantiate a collection (here IndexSet) from an other collection (here a range of numbers).
use indexmap::set::IndexSet;
const COUNTS: [usize; 5] = [1, 2, 4, 8, 16];
fn main() {
for (i, count) in COUNTS.iter().copied().enumerate() {
let length = count/2;
let set = (0..length).collect::<IndexSet<_>>();
}
}
See the playground.

You need to statically add the array size:
let indices: [usize; 5] = Vec::from_iter(0..length).try_into().unwrap();
Which invalidates the purpouse of your code. That said, IndexSet implements FromIterator:
use indexmap::IndexSet;
const COUNTS: [usize; 5] = [1, 2, 4, 8, 16];
fn main() {
for (i, count) in COUNTS.iter().enumerate() {
let length: usize = *count / 2;
let set: IndexSet<usize> = IndexSet::from_iter(0..length);
}
}
Playground

Related

rust macro, how to control the different vec have the same length?

code first:
use std::collections::HashMap;
macro_rules! arr{
([$($t:expr=>[$($c:expr),*]),*]) => {
vec![
$({
let mut m = HashMap::new();
m.insert($t, vec![$($c),*]);
m
}),*
]
};
}
fn main() {
let a = arr!([
"A"=>[1,2,3],
"B"=>[3,4]
]);
println!("{:?}", a);
//print: [{"A": [1, 2, 3]}, {"B": [3, 4]}]
}
I have above macro to generate a vec, contains several HashMap, in which these HashMap value is a vec as well,
{"A": [1, 2, 3]} => vec value length: 3,
{"B": [3, 4]} => vec value length: 2,
I wanna all the HashMap have the same length,
how to write in the macro to control this?
You can change the macro so that it creates a block (second set of {} encapsulating the macro definition) that you can set helper variables in and do a second pass over your vector, resizing anything that is smaller than the largest array.
In this case I've resized the arrays with the default value of the type to keep it simple. You may wish to wrap the data in Some().
This:
use std::cmp;
use std::collections::HashMap;
use std::default::Default;
macro_rules! arr{
([$($t:expr=>[$($c:expr),*]),*]) => {{
let mut max = 0;
let mut result = vec![
$({
let mut m = HashMap::new();
m.insert($t, vec![$($c),*]);
// Simply unwrap here as we know we inserted at this key above
max = cmp::max(max, m.get($t).unwrap().len());
m
}),*
];
for m in result.iter_mut() {
for v in m.values_mut() {
if v.len() < max {
v.resize_with(max, Default::default);
}
}
}
result
}};
}
fn main() {
let a = arr!([
"A"=>[1,2,3],
"B"=>[3,4]
]);
println!("{:?}", a);
//print: [{"A": [1, 2, 3]}, {"B": [3, 4]}]
}
Yields:
[{"A": [1, 2, 3]}, {"B": [3, 4, 0]}]

Insert into Rust array in place, push other elements down

I'm trying to do the following in Rust, specifically using arrays (I don't want to use vectors here, and want elements pushed out of the array if we're done).
let mut x = [1, 2, 3, 4, 5];
// array, number to insert, place to be inserted at
insert_in_place(&x, 7, 1);
// x is now [1, 7, 2, 3, 4];
How do you implement insert_in_place?
I think there's a way to do this using slices, but I'm still learning and wondering if there's a really elegant way to do this kind of thing.
fn insert_in_place<T>(array: &mut [T], value: T, index: usize) {
*array.last_mut().unwrap() = value;
array[index..].rotate_right(1);
}
Try it online!
Or equivalently:
fn insert_in_place<T>(array: &mut [T], value: T, index: usize) {
array[index..].rotate_right(1);
array[index] = value;
}
Try it online!
Iterate the slice, skipping elements before the index of the one you need to insert. Then swap each element with its previous element (or, for the first one, use the item to add).
fn insert_in_place<T>(x: &mut [T], new: T, index: usize) {
let mut next = new;
for e in x.iter_mut().skip(index) {
std::mem::swap(e, &mut next);
}
}
fn main() {
let mut x = [1, 2, 3, 4, 5];
// array, number to insert, place to be inserted at
insert_in_place(&mut x, 7, 1);
// x is now [1, 7, 2, 3, 4];
println!("{:?}", x);
}

How to obtain the chunk index in Rayon's par_chunks_mut

I have some data and I want to process it and use it to fill an array that already exists. For example suppose I want to repeat each value 4 times (playground):
use rayon::prelude::*; // 1.3.0
fn main() {
let input = vec![4, 7, 2, 3, 5, 8];
// This already exists.
let mut output = vec![0; input.len() * 4];
output.par_chunks_mut(4).for_each(|slice| {
for x in slice.iter_mut() {
*x = input[?];
}
});
}
This almost works but Rayon doesn't pass the chunk index to me so I can't put anything in input[?]. Is there an efficient solution?
The easiest thing to do is avoid the need for an index at all. For this example, we can just zip the iterators:
use rayon::prelude::*; // 1.3.0
fn main() {
let input = vec![4, 7, 2, 3, 5, 8];
let mut output = vec![0; input.len() * 4];
// Can also use `.zip(&input)` if you don't want to give up ownership
output.par_chunks_mut(4).zip(input).for_each(|(o, i)| {
for o in o {
*o = i
}
});
println!("{:?}", output)
}
For traditional iterators, this style of implementation is beneficial as it avoids unneeded bounds checks which would otherwise be handled by the iterator. I'm not sure that Rayon benefits from the exact same thing, but I also don't see any reason it wouldn't.
Rayon provides an enumerate() function for most of its iterators that works just like the non-parallel counterpart:
let input = vec![4, 7, 2, 3, 5, 8];
let mut output = vec![0; input.len() * 4];
output.par_chunks_mut(4).enumerate().for_each(|(i, slice)| {
for x in slice.iter_mut() {
*x = input[i];
}
});

How to idiomatically check if a 2-dimensional vector is a table? [duplicate]

Given a vector of vectors of some value T, ie. Vec<Vec<T>>.
What's the idiomatic way to check if the inner vectors have the same length? (without external dependencies)
That is, true if all the inner vectors have the same length, and false otherwise.
You can use the all method to check if all elements of an iterator match a predicate. Then just compare against the first element in the list.
fn main() {
let vec_of_vecs = vec![
vec![1, 2, 3],
vec![1, 2, 3],
vec![1, 2, 3],
vec![1, 2, 3],
vec![1, 2, 3],
vec![1, 2, 3, 4], // remove this to prove that it works for both cases
];
let all_same_length = vec_of_vecs
.iter()
.all(|ref v| v.len() == vec_of_vecs[0].len());
if all_same_length {
println!("They're all the same");
} else {
println!("They are not the same");
}
}
An other solution more generic and idiomatic in my opinion:
fn all_eq_len<'a, T, E: 'a>(collection: T) -> bool
where
T: IntoIterator<Item = &'a Vec<E>>,
{
let mut iter = collection.into_iter();
if let Some(first) = iter.next() {
let len = first.len();
iter.all(|v| v.len() == len)
} else {
true
}
}
And of course using itertools:
use itertools::Itertools;
vec_of_vecs.iter().map(|v| v.len()).all_equal()

Explicit partial array initialisation in Rust

In C, I can write int foo[100] = { 7, 8 }; and I will get [7, 8, 0, 0, 0...].
This allows me to explicitly and concisely choose initial values for a contiguous group of elements at the beginning of the array, and the remainder will be initialised as if they had static storage duration (i.e. to the zero value of the appropriate type).
Is there an equivalent in Rust?
To the best of my knowledge, there is no such shortcut. You do have a few options, though.
The direct syntax
The direct syntax to initialize an array works with Copy types (integers are Copy):
let array = [0; 1024];
initializes an array of 1024 elements with all 0s.
Based on this, you can afterwards modify the array:
let array = {
let mut array = [0; 1024];
array[0] = 7;
array[1] = 8;
array
};
Note the trick of using a block expression to isolate the mutability to a smaller section of the code; we'll reuse it below.
The iterator syntax
There is also support to initialize an array from an iterator:
let array = {
let mut array = [0; 1024];
for (i, element) in array.iter_mut().enumerate().take(2) {
*element = (i + 7);
}
array
};
And you can even (optionally) start from an uninitialized state, using an unsafe block:
let array = unsafe {
// Create an uninitialized array.
let mut array: [i32; 10] = mem::uninitialized();
let nonzero = 2;
for (i, element) in array.iter_mut().enumerate().take(nonzero) {
// Overwrite `element` without running the destructor of the old value.
ptr::write(element, i + 7)
}
for element in array.iter_mut().skip(nonzero) {
// Overwrite `element` without running the destructor of the old value.
ptr::write(element, 0)
}
array
};
The shorter iterator syntax
There is a shorter form, based on clone_from_slice, it is currently unstable however.
#![feature(clone_from_slice)]
let array = {
let mut array = [0; 32];
// Override beginning of array
array.clone_from_slice(&[7, 8]);
array
};
Here is macro
macro_rules! array {
($($v:expr),*) => (
{
let mut array = Default::default();
{
let mut e = <_ as ::std::convert::AsMut<[_]>>::as_mut(&mut array).iter_mut();
$(*e.next().unwrap() = $v);*;
}
array
}
)
}
fn main() {
let a: [usize; 5] = array!(7, 8);
assert_eq!([7, 8, 0, 0, 0], a);
}

Resources