How to initialize an array in a struct definition? - struct

How can I set the array values to 0 in this struct? This is obviously wrong. How do I do it correctly?
struct Game {
board: [[i32; 3]; 3] = [[0, 0, 0], [0, 0, 0], [0, 0, 0]];
}
In a function this would have been:
let board: [[i32; 3]; 3] = [[0, 0, 0], [0, 0, 0], [0, 0, 0]];

You cannot initialize fields in struct definition because it is behaviour while struct must contain only data.
This should work:
struct Game {
board: [[i32; 3]; 3]
}
impl Game{
fn new()->Self{
Self{
board: [[0, 0, 0], [0, 0, 0], [0, 0, 0]]
}
}
}
...
let game = Game::new();

If you want to define a default value for a struct, you can implement the Default trait for it.
In the case of a struct containing values that themselves implement Default, it is as simple as adding #[derive(Default)]:
#[derive(Default,Debug)]
struct Game {
board: [[i32; 3]; 3]
}
fn main() {
let game : Game = Default::default();
println!("{:?}", game);
}
Alternatively, if your struct is more complex, you can implement Default by hand.
Playground
The advantage of using Default over writing a constructor (as in Angelicos' answer) is that:
You can use derive to implement it
Data structures which contain your struct can also use derive
You can use the ..Default::default() struct update syntax to specify some fields of a struct, while defaulting the rest.
See also:
The Default Trait in "Rust Design Patterns"
Derivable Traits in "The Rust Book"

Related

Sharing reference from a mutable method

Rust does not allow borrowing multiple mutable references. I understand that. But I can not find any elegant way to implement a few algorithms. Below is a simplified version of one such algorithm. The Ladder struct hands out slices of ever increasing sequence of numbers, such as, [0], [0, 1], [0, 1, 2] and so on.
struct Ladder {
position: usize,
data: [u8; 10],
}
impl Ladder {
fn get_next(&mut self) -> &[u8] {
self.position += 1;
&(self.data[0..self.position])
}
fn new() -> Ladder {
Ladder {
position: 0,
data: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9],
}
}
}
I need to call get_next() a couple of times, collect the returned sequences and call a closure that will do something with those sequences.
fn test_ladder(consumer: impl Fn(&[&[u8]])) {
let mut l = Ladder::new();
let mut steps: [&[u8]; 3] = [&[]; 3];
steps[0] = l.get_next();
steps[1] = l.get_next();
steps[2] = l.get_next();
consumer(&steps);
}
fn main() {
test_ladder(|steps| {
for seq in steps {
println!("{:?}", *seq);
}
});
}
It is a non-allocating algorithm. I can not use std::Vec.
What is the idiomatic way to approach problems like this?
The problem here is that you can't keep references to something that you mutate, and .get_next() is allowed to mutate data. What you need to do is separate the data from the mutation. You can do that by only keeping a reference to the original data.
Creating a sequence of elements sounds a lot like an iterator, so here's an example:
struct LadderIter<'a> {
position: usize,
data: &'a [u8],
}
impl<'a> LadderIter<'a> {
fn new(data: &'a [u8]) -> LadderIter<'a> {
LadderIter { position: 0, data }
}
}
impl<'a> Iterator for LadderIter<'a> {
type Item = &'a [u8];
fn next(&mut self) -> Option<Self::Item> {
if self.position == self.data.len() {
None
} else {
self.position += 1;
Some(&self.data[0..self.position])
}
}
}
Which you can then use as an iterator:
for step in LadderIter::new(&[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]) {
println!("{step:?}");
}
[0]
[0, 1]
[0, 1, 2]
[0, 1, 2, 3]
[0, 1, 2, 3, 4]
[0, 1, 2, 3, 4, 5]
[0, 1, 2, 3, 4, 5, 6]
[0, 1, 2, 3, 4, 5, 6, 7]
[0, 1, 2, 3, 4, 5, 6, 7, 8]
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
Or in your specific use-case:
let data = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
let mut ladder = LadderIter::new(&data);
let steps: [&[u8]; 3] = [
ladder.next().unwrap(),
ladder.next().unwrap(),
ladder.next().unwrap(),
];
Another approach is to use interior mutability. Since you are only modifying position, you can use the zero-cost Cell:
use std::cell::Cell;
struct Ladder {
position: Cell<usize>,
data: [u8; 10],
}
impl Ladder {
fn get_next(&self) -> &[u8] {
self.position.set(self.position.get() + 1);
&self.data[0..self.position.get()]
}
fn new() -> Ladder {
Ladder {
position: Cell::new(0),
data: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9],
}
}
}

With a HashMap<T, HashMap<T, i32>>, how can I insert the inner HashMap by the outer key?

For example, if I have a vector [1, 2], and I want to build a HashMap like <1: <2: 0>>, how can I insert the key and value? (The 0 is a default number), you can use x[0], x[1] to describe the elements in the vector.
I try to use map.insert(k,v), however, I don't know how to write the second parameter.
If I understand your question correctly, you are trying to, given a vector [n, m], insert a (key, value) pair into a HashMap where the key is n and the value is another HashMap, containing the (key, value) pair, (m, 0). That is, in JSON:
{ n: { m: 0 } }
As one commenter mentioned, you'll need to create the second map.
use std::collections::HashMap;
// I have arbitrarily picked `u8` for `T` here.
let mut map: HashMap<u8, HashMap<u8, i32>> = HashMap::new();
// And here's the vector we're given, maybe as a function argument:
let v: Vec<u8> = vec![1, 2];
// So we start by constructing our sub-map:
let mut sub_map: HashMap<u8, i32> = HashMap::new();
sub_map.insert(v[1], 0);
// And then we insert it into our outer map:
map.insert(v[0], sub_map);
So this solution answers your question, but it's kind of a crummy one, because I can easily imagine that you will want to process any number of 2-vectors and generate a more complicated map; for example, perhaps you want to, given this set of inputs:
[1, 2], [1, 3], [2, 5], [3, 5]
arrive at this map:
{
1: { 2: 0, 3: 0 },
2: { 5: 0 },
3: { 5: 0 }
}
The above technique would have blown the { 2: 0 } out of the first inner value when inserting the { 3: 0 }. What we probably want instead is a kind of "update or insert" (I have heard database guys use the term "upsert").
So we want something like this:
map.entry(v[0]).or_default().insert(v[1], 0);
The .or_default() will insert an empty inner HashMap (the type returned by HashMap::default()) keyed to the value of v[0] if the outer HashMap doesn't yet have one (then the .insert(v[1], 0) inserts the values you want in the inner map).
So in action it might look something like this:
let v: Vec<Vec<u8>> = vec![
vec![1, 2],
vec![1, 3],
vec![2, 5],
vec![3, 5],
];
let mut map: HashMap<u8, HashMap<u8, i32>> = HashMap::new();
for u in v.iter() {
map.entry(u[0]).or_default().insert(u[1], 0);
}
println!("{:#?}", &map);
/* should produce something like
{
1: {
2: 0,
3: 0,
},
2: {
5: 0,
},
3: {
5: 0,
},
}
*/

How to perform element-wise subtraction between two vectors?

I have to Vecs: vec_a and vec_b. Both the same size. I want to perform element-wise subtraction between the two vectors and save the answer in a third vector vec_c. For example:
vec_a = [1, 2, 3]
vec_b = [0, 2, -3]
vec_c = vec_a - vec_b = [1, 0, 6]
The solution I've come with is this function:
pub fn elementwise_subtraction(vec_a: Vec<i32>, vec_b: Vec<i32>) -> Vec<i32> {
let mut vec_c = Vec::new();
for i in 0..vec_a.len() {
vec_c.push(vec_a[i] - vec_b[i]);
}
vec_c
}
I feel like this is a bit verbose for a pretty simple operation. Is there a better/more idiomatic way to do this?
There is no such thing built in, you have to implement it yourself or use a third-party crate.
Anyway, you can continue to improve your code using functional programming:
pub fn elementwise_subtraction(vec_a: Vec<i32>, vec_b: Vec<i32>) -> Vec<i32> {
vec_a.into_iter().zip(vec_b).map(|(a, b)| a - b).collect()
}
let vec_a = vec![1, 2, 3];
let vec_b = vec![0, 2, -3];
let vec_c = elementwise_subtraction(vec_a, vec_b);
assert_eq!(vec_c, [1, 0, 6])
If you want to make it more generic (e.g. accepting both slices or Vec, any subtractable type):
use std::ops::Sub;
pub fn elementwise_subtraction<N, IA, IB, F>(a: IA, b: IB) -> F
where
N: Sub,
IA: IntoIterator<Item = N>,
IB: IntoIterator<Item = N>,
F: FromIterator<N> + FromIterator<<N as Sub>::Output>,
{
a.into_iter().zip(b).map(|(a, b)| a - b).collect()
}
let vec_a = [1, 2, 3];
let vec_b = [0, 2, -3];
let vec_c: Vec<_> = elementwise_subtraction(vec_a, vec_b);
assert_eq!(vec_c, [1, 0, 6])
Try it on playground
You'll need to use zip and map:
fn main() {
let vec_a = [1, 2, 3];
let vec_b = [0, 2, -3];
let vec_c: Vec<i32> = vec_a
.iter()
.zip(vec_b)
.map(|(elem_a, elem_b)| elem_a - elem_b)
.collect();
for elem_c in vec_c {
println!("{}", elem_c);
}
}
Your method is likely the most efficient way since it uses straight indexing, but an iterator method could look like this:
assert_eq!(
vec_a
.iter()
.zip(vec_b)
.map(|(a, b)| a - b)
.collect::<Vec<_>>(),
vec![1, 0, 6]
);
"Better" is always subjective, so if performance is your priority you should benchmark different methods; I've been surprised by results before.

Permutations with replacement in rust?

I'd like to write a generic function that can make all unique vectors where each index has a series of values.
Easiest to illustrate with an example.
for i in (1..3).combinations_with_replacement(3) {
println!("{:?}",i);
}
Produces the ouput
[1, 1, 1]
[1, 1, 2]
[1, 2, 2]
[2, 2, 2]
Which is not satisfactory because it's missing members like
[1, 2, 1]
[2, 1, 2]
[2, 2, 1]
So I also tried permutations(3) but since their are more positions than items in the iterator, the iterator is empty. There also doesn't appear to be a permutations_with_replacement but maybe that'd be the name of the function I'm looking for.
In this case you could accomplish the task with 3 nested for loops but this is ugly and not a general solution. I think a recursive backtracking solution could do it too but seems like their should be something in itertools that I'm missing.
Here's another example of what I want but with code written a few languages that aren't rust.
Using itertools, based on #Ry-'s suggestion:
for i in (1..=3).map(|_| 1..=2).multi_cartesian_product() {
println!("{i:?}");
}
Output:
[1, 1, 1]
[1, 1, 2]
[1, 2, 1]
[1, 2, 2]
[2, 1, 1]
[2, 1, 2]
[2, 2, 1]
[2, 2, 2]
Playground
I'm not sure how this can be done using itertools, but here is one way to achieve the same result in plain Rust.
pub struct PermutationsReplacementIter<I> {
items: Vec<I>,
permutation: Vec<usize>,
group_len: usize,
finished: bool,
}
impl<I: Copy> PermutationsReplacementIter<I> {
fn increment_permutation(&mut self) -> bool {
let mut idx = 0;
loop {
if idx >= self.permutation.len() {
return true;
}
self.permutation[idx] += 1;
if self.permutation[idx] >= self.items.len() {
self.permutation[idx] = 0;
idx += 1;
} else {
return false;
}
}
}
fn build_vec(&self) -> Vec<I> {
let mut vec = Vec::with_capacity(self.group_len);
for idx in &self.permutation {
vec.push(self.items[*idx]);
}
vec
}
}
impl<I: Copy> Iterator for PermutationsReplacementIter<I> {
type Item = Vec<I>;
fn next(&mut self) -> Option<Self::Item> {
if self.finished {
return None;
}
let item = self.build_vec();
if self.increment_permutation() {
self.finished = true;
}
Some(item)
}
}
pub trait ToPermutationsWithReplacement {
type Iter;
fn permutations_with_replacement(self, group_len: usize) -> Self::Iter;
}
impl<I: Iterator> ToPermutationsWithReplacement for I {
type Iter = PermutationsReplacementIter<<I as Iterator>::Item>;
fn permutations_with_replacement(self, group_len: usize) -> Self::Iter {
let items = self.collect::<Vec<_>>();
PermutationsReplacementIter {
permutation: vec![0; group_len],
group_len,
finished: group_len == 0 || items.len() == 0,
items,
}
}
}
Then it can be used similarly to combinations_with_replacement.
for x in (1..3).permutations_with_replacement(3) {
println!("{:?}", x);
}
// Output:
[1, 1, 1]
[2, 1, 1]
[1, 2, 1]
[2, 2, 1]
[1, 1, 2]
[2, 1, 2]
[1, 2, 2]
[2, 2, 2]
Playground Link
You can also put it on any iterator where the elements implement Copy. However, I wouldn't recommend it. The time complexity for this task is extremely bad. For an input iterator of n elements in groups of length m, this will create an iterator of about n^m items assuming my math is correct.

How to pass a 2-dimensional Vector to a function in rust?

I'm trying to pass a 2-d array to a function but I cant figure out how to specify the expected type of the function.
My code looks like this
fn main() {
let ker = vec![[-1, -1, -1], [-1, 8, -1], [-1, -1, -1]];
do_schtuff(ker);
}
fn do_schtuff(k: Vec<Vec<i32>>) {
println!("{:?}", k);
}
P.S.: I'm new to rust so any advice would be really appreciated! Thanks!
You don't actually have a two dimensional vector there. You have a vector of integer arrays. You need to change your code to actually use a vector with integer vectors in it:
fn main() {
let ker = vec![vec![-1, -1, -1], vec![-1, 8, -1], vec![-1, -1, -1]];
do_schtuff(ker);
}
fn do_schtuff(k: Vec<Vec<i32>>) {
println!("{:?}", k);
}
Though it almost certainly would be better to not move the vector and give ownership to the do_schtuff function, but instead to pass the vector as a reference to a slice:
fn main() {
let ker = vec![vec![-1, -1, -1], vec![-1, 8, -1], vec![-1, -1, -1]];
do_schtuff(&ker[..]);
}
fn do_schtuff(k: &[Vec<i32>]) { // Note it is more idiomatic to use a slice.
println!("{:?}", k);
}

Resources