I have a struct with an array
struct Model<const D: usize> {
b: f64,
j: f64,
arr: Array<f64, Dim<[Ix, D]>,
}
And I noticed that I cannot access the value in arr via [usize; D], e.g.
impl<const D: usize> for Model<D> {
fn sum(&self) -> f64 {
// ...
let mut cursor = [0; D];
sum += arr[[cursor]]; // fail with error
}
}
because cursor is not implementing corresponding traits:
the trait bound [i32; D]: NdIndex<ndarray::Dim<[usize; D]>> is not satisfied
I would expect for an arbitrary D > 0 ndarray should be able to handle it. Yet it is not possible. I am wondering if there is a workaround for this kind of isssue.
Related
Is there any comfortable way to get value from Vec<Vec<T>>? I can do it for a normal 1D Vec: vec.get(), but if vec is Vec<Vec>, get returns the Some<Vec<T>>, not the value of T. Is there a nice way to 'get' value from 2D matrix (Vec<Vec<T>>)?
Option::and_then lets you chain optional return values (o.and_then(f) is equivalent to o.map(f).flatten()):
vec.get(i).and_then(|v| v.get(j))
It also easily extends to higher dimensions:
vec
.get(i)
.and_then(|v| v.get(j))
.and_then(|v| v.get(k))
.and_then(|v| v.get(l))
// and so on
#Aplet123 is of course right, that's the way to go and his answer should be marked correct.
But in case you wonder how to make this prettier, you could wrap it in a custom trait for Vec<Vec<T>>:
trait Get2D {
type Val;
fn get2d(&self, i: usize, j: usize) -> Option<&Self::Val>;
fn get2d_mut(&mut self, i: usize, j: usize) -> Option<&mut Self::Val>;
}
impl<T> Get2D for Vec<Vec<T>> {
type Val = T;
fn get2d(&self, i: usize, j: usize) -> Option<&T> {
self.get(i).and_then(|e| e.get(j))
}
fn get2d_mut(&mut self, i: usize, j: usize) -> Option<&mut T> {
self.get_mut(i).and_then(|e| e.get_mut(j))
}
}
fn main() {
let mut data: Vec<Vec<i32>> = vec![vec![1, 2, 3], vec![4, 5, 6]];
println!("{}", data.get2d(1, 1).unwrap());
*data.get2d_mut(0, 1).unwrap() = 42;
println!("{:?}", data);
}
5
[[1, 42, 3], [4, 5, 6]]
I am trying to write a function template which I want to have the following signature
pub fn convert_to_one_hot<T>(category_id: T, num_classes: usize) -> Vec<bool> {...}
Here T can be usize or Vec<usize>. How should I determine the trait bounds for T to
write such a function ?
In the following are instances of the function for the two cases :
When T is usize
pub fn convert_to_one_hot(category_id: usize, num_classes: usize) -> Vec<bool> {
let mut one_hot = Vec::<bool>::with_capacity(num_classes);
for index in 0usize..num_classes{
one_hot[index] = false;
}
one_hot[category_id] = true;
one_hot
}
When T is Vec<usize>
pub fn convert_to_one_hot(category_id: Vec<usize>, num_classes: usize) -> Vec<bool> {
let mut one_hot = Vec::<bool>::with_capacity(num_classes);
for index in 0usize..num_classes {
one_hot[index] = false;
}
for category in category_id{
one_hot[category] = true;
}
one_hot
}
You can create a helper trait and implement it for usize and Vec<T>:
pub trait ToOneHot {
fn convert(self, num_clases: usize) -> Vec<bool>;
}
impl ToOneHot for usize {
fn convert(self, num_classes: usize) -> Vec<bool> {
let mut one_hot = vec![false; num_classes];
one_hot[self] = true;
one_hot
}
}
impl ToOneHot for Vec<usize> {
fn convert(self, num_classes: usize) -> Vec<bool> {
let mut one_hot = vec![false; num_classes];
for category in self {
one_hot[category] = true;
}
one_hot
}
}
With that trait in place, the implementation of convert_to_one_hot becomes trivial:
pub fn convert_to_one_hot<T: ToOneHot>(category_id: T, num_classes: usize) -> Vec<bool> {
category_id.convert(num_classes)
}
Playground
Note that your vector creation was incorrect. Vec::with_capacity() is just an optimization, it does pre-allocate the space, but still returns an empty vector, so assigning elements to it will panic because it's out of bounds. You need to either call push() to append elements to the vector or create a non-empty vector to begin with, as shown in the edited code.
You can actually make do without a custom trait here, without sacrificing much convenience. If you accept an IntoIterator<Item = usize>, then you can pass in anything that can be iterated to yield usize items. This include Vec<usize> and Option<usize>. The latter can be used to conveniently pass in a single usize value.
pub fn convert_to_one_hot<I>(category_id: I, num_classes: usize) -> Vec<bool>
where
I: IntoIterator<Item = usize>,
{
let mut result = vec![false; num_classes];
for id in category_id {
result[id] = true;
}
result
}
This function can be called for vectors like this
convert_to_one_hot(vec![1, 3, 5], 6)
and for single integer values like this
convert_to_one_hot(Some(3), 6)
(Playground)
My intention is to create a dynamic 2D array with multiple rows and columns. How can I achieve that?
Attempted solution
The following line of code works but the array ends up having only a single row.
let matrix: &mut [&mut [i32]] = &mut [&mut [0; 3]];
In order to create an array with 3 rows instead of one I tried the following piece of code but it produced a compile time error.
let matrix: &mut [&mut [i32]] = &mut [&mut [0; 3]; 3];
mismatched types
expected slice `[&mut [i32]]`, found array `[&mut [{integer}; 3]; 3]`
note: expected mutable reference `&mut [&mut [i32]]`
found mutable reference `&mut [&mut [{integer}; 3]; 3]`rustc(E0308)
main.rs(7, 17): expected due to this
main.rs(7, 37): expected slice `[&mut [i32]]`, found array `[&mut [{integer}; 3]; 3]`
Based on your question it looks like you're trying to use a matrix object.
There are multiple ways to do that in rust:
Compile-Time matrices:
Using const generics it's now very easy to define the matrix object with an array of arrays:
pub struct Matrix<T, const ROWS: usize, const COLS: usize> {
data: [[T; COLS]; ROWS],
}
impl<T, const ROWS: usize, const COLS: usize> Matrix<T, ROWS, COLS> {
pub fn new(data: [[T; COLS]; ROWS]) -> Self {
Self { data }
}
}
impl<T, const ROWS: usize, const COLS: usize> Index<(usize, usize)> for Matrix<T, ROWS, COLS> {
type Output = T;
fn index(&self, index: (usize, usize)) -> &Self::Output {
&self.data[index.0][index.1]
}
}
Here, the amount of rows and columns are hard-coded into the data-type.
So to resize you need to a create a new object and all types must be known (defined) at compile time.
Dynamic matrices:
If you want run-time (dynamic) sizing, the simplest solution is to use a vector of vectors:
pub struct Matrix<T> {
data: Vec<Vec<T>>,
}
impl<T> Matrix<T> {
pub fn new(data: Vec<Vec<T>>) -> Self {
Self { data }
}
}
impl<T> Index<(usize, usize)> for Matrix<T> {
type Output = T;
fn index(&self, index: (usize, usize)) -> &Self::Output {
&self.data[index.0][index.1]
}
}
Note that since vectors are pointers to memory on the heap, the items won't usually be contiguous in memory.
You can build contiguous dynamic matrices by using a single vector and indices to map to chunks of it:
pub struct Matrix<T> {
rows: usize,
cols: usize,
data: Vec<T>,
}
impl<T> Matrix<T> {
pub fn new(rows: usize, cols: usize, data: Vec<T>) -> Self {
assert_eq!(rows * cols, data.len());
Self { rows, cols, data }
}
}
impl<T> Index<(usize, usize)> for Matrix<T> {
type Output = T;
fn index(&self, index: (usize, usize)) -> &Self::Output {
&self.data[index.0 * self.cols + index.1]
}
}
Is it possible to make a bind to object method? For example, I have a vector and a lot of functions which do something if some item exists in the vector. I would implement it as follows:
fn perform_if_exists(item: u8, vector: &Vec<u8>, func: fn(usize)) {
let idx = vector.iter().position(|i| *i == item );
match idx {
Some(i) => func(i),
None => {},
}
}
fn main() {
let v: Vec<u8> = vec![1, 2, 3];
perform_if_exists(1, &v, Vec<_>::remove);
}
but it gives a lot of errors. I think they are reasonable but it's because I don't understand how to put vector's method as argument to a function.
Is it possible
Sure it is. You have to fix the multiple cascading errors first:
Invalid syntax: Vec<_>::remove isn't valid.
Incompatible argument types: Vec::remove modifies a Vec, so you have to pass in a Vec somehow.
Mutability: Vec::remove modifies a Vec, so you have to declare that the function is allowed to do so.
Vec::remove returns the removed value, so you have to allow the function to return a value, even if it's thrown away.
fn perform_if_exists<F, R>(item: u8, vector: &mut Vec<u8>, func: F)
where
F: Fn(&mut Vec<u8>, usize) -> R,
{
let idx = vector.iter().position(|i| *i == item);
if let Some(i) = idx {
func(vector, i);
}
}
fn main() {
let mut v = vec![1, 2, 3];
perform_if_exists(1, &mut v, Vec::remove);
println!("{:?}", v);
}
I switched to a generic as that's generally how you will accept closures. A function pointer is fine but more restrictive.
A method in Rust is nothing more than a function, which also takes a first self parameter. The method Vec::remove takes two arguments: &mut self and index: usize. The self parameter is always of type Self, which is Vec<u8> in this case. The complete type of Vec::<u8>::remove is: fn(&mut Vec<u8>, usize) -> u8 (yes it also returns the removed element).
After changing the type in your code (+ a few minor mistakes), it works:
// vvv-- has to be mutable
fn perform_if_exists(item: u8, vector: &mut Vec<u8>, func: fn(&mut Vec<u8>, usize) -> u8) {
let idx = vector.iter().position(|i| *i == item );
match idx {
Some(i) => {
func(vector, i);
},
None => {},
}
}
fn main() {
let mut v: Vec<u8> = vec![1, 2, 3];
perform_if_exists(1, &mut v, Vec::remove);
}
But fn(...) -> ... types are raw pointer types and just work for ordinary functions. Often you also want to enable the user to pass anything that is "callable", like closures. There are traits exactly for that purpose: Fn(...) -> ....
Let me propose another solution:
fn perform_if_exists<T, F, R>(item: T, vector: &mut Vec<T>, func: F) -> Option<R>
where F: FnOnce(&mut Vec<T>, usize) -> R,
T: PartialEq
{
let idx = vector.iter().position(|i| *i == item );
idx.map(|i| func(vector, i))
}
This solution is far more generic as it allows arbitrary item types, arbitrary "callable" types and returns the value that is returned by the given function. Note that the main function didn't change; the solution is more generic, but all old uses still work.
Even when I implement IndexMut for my struct, I cannot get a mutable reference to an element of structure inner vector.
use std::ops::{Index, IndexMut};
struct Test<T> {
data: Vec<T>,
}
impl<T> Index<usize> for Test<T> {
type Output = T;
fn index<'a>(&'a self, idx: usize) -> &'a T {
return &self.data[idx];
}
}
impl<T> IndexMut<usize> for Test<T> {
fn index_mut<'a>(&'a mut self, idx: usize) -> &'a mut T {
// even here I cannot get mutable reference to self.data[idx]
return self.data.index_mut(idx);
}
}
fn main() {
let mut a: Test<i32> = Test { data: Vec::new() };
a.data.push(1);
a.data.push(2);
a.data.push(3);
let mut b = a[1];
b = 10;
// will print `[1, 2, 3]` instead of [1, 10, 3]
println!("[{}, {}, {}]", a.data[0], a.data[1], a.data[2]);
}
How can I use index_mut to get a mutable reference? Is it possible?
You're almost there. Change this:
let mut b = a[1];
b = 10;
to this:
let b = &mut a[1];
*b = 10;
Indexing syntax returns the value itself, not a reference to it. Your code extracts one i32 from your vector and modifies the variable - naturally, it does not affect the vector itself. In order to obtain a reference through the index, you need to write it explicitly.
This is fairly natural: when you use indexing to access elements of a slice or an array, you get the values of the elements, not references to them, and in order to get a reference you need to write it explicitly.