Mutidimensional array as parameter

how to pass an multidimensional array to a function without specify the row and column
is it possible to pass a multidimensional array with out specify it row and colum

eg
fn change_value(arr: &mut [i32]) {
arr[1] = 10;
}

fn main() {
let mut arr: [i32; 4] = [1, 2, 3, 4];
change_value(&mut arr);
println!(“this is {}”, arr[1]);
}
here it is a single dimensional array
we pass the array only by specify it’s type i32
like that is t possible to pass a multidimensional array by specify it’s type only

I suggest avoiding the array type in Rust. Usually Vec is a better choice, especially if sizes are larger than a few elements.

1 Like

did you know,how to initialize multidimensional vector and pass value to it

To initialize a vector it’s as simple as:

let _ = Vec::new();

To fill it with values, you can say for example:

let _ = (0..10).map(|_| 1).collect::<Vec<usize>>();

And to make a multi dimensional uniform vector:

let width = 10;
let height = 15;
let default_value = 20;
let v: Vec<Vec<usize>> = (0..width)
        .map(|_| 
            (0..height)
            .map(|_| default_value)
            .collect()
        ).collect();

This is indexed v[x][y]. If you just want to allocate space for these, but not actually fill them with values:

let v = (0..width).map(|_| Vec::with_capacity(height)).collect::<Vec<Vec<usize>>>();

If you want a “jagged array” (where each row is allowed to have a different length), then use Vec<Vec<…>>.

If you want to enforce a rectangular shape, then use Vec<…> of size width * height, and vec[x + y * width] to get individual elements (that’s the same as you’d do in C for variable-size 2d array). I use imgref to formalize this.

1 Like

what about 3d vector
what change should i bring i above syntax

is it possible to remove or insert a element from particular position of 2d vector without iterating like in 1d vector
eg:
b2.remove(3);
b2.insert(3,3);

Well, since these are iterators, you can just nest another one:

let width = 10;
let height = 15;
let depth = 30;
let default_value = 20;
let v: Vec<Vec<Vec<usize>>> = 
        (0..width)
        .map(|_| 
            (0..height)
            .map(|_| 
                 (0..depth)
                 .map(|_| default_value)
                 .collect()
            ).collect()
        ).collect();

Or you can take the ergonomic route, and use the vec! macro as described in post #10

When you access an element in a Vec<T>, you do it like so:

let foo: Vec<T> = Vec::new();
//Fill foo
let x = foo[10];

Therefore, if we treat it like a 1D vector, we can say:

let mut foo: Vec<usize> = Vec::new();
//Fill foo
foo.remove(10);

If we have a multidimensional array we can access a one dimensional vector from a two dimensional vector:

let mut foo: Vec<Vec<usize>> = Vec::new();
//Fill foo
let x: &mut Vec<usize> = &mut foo[2];
x.remove(10);

Or for a 3D example:

let mut foo: Vec<Vec<Vec<usize>>> = Vec::new();
//Fill foo
let x: &mut Vec<Vec<usize>> = &mut foo[2];
let y: &mut Vec<usize>> = &mut x[1];
y.remove(10);
1 Like

We have vec![] macro for it!

let v = vec![vec![vec![default_value; depth]; height]; width];
2 Likes

Right! I knew I was forgetting something! The vec! macro is definitely a better solution to this!

Alternatively to all of this, if you’re just working with a few small array types like [[T; 4]; 4], you could use a generic approach:

fn mutate_2d<V: AsMut<[i32]>>(array: &mut [V]) {
    array[1].as_mut()[2] = 1;
}

fn sum_2d<V: AsRef<[i32]>>(array: &[V]) -> i32 {
    array.iter()
        .map(|v| v.as_ref().iter().sum::<i32>())
        .sum()
}

fn main() {
    let mut matrix = [[1, 0, 0], [0, 1, 0], [0, 0, 1]];
    mutate_2d(&mut matrix);
    assert_eq!(sum_2d(&matrix), 5);
}

In fact, this function signature even works with vectors. Because it is generic, rust will generate separate, optimized code for each case:

let mut vec_of_array = vec![[1, 0, 0], [0, 1, 0], [0, 0, 1]];
let mut array_of_vec = [vec![1, 0, 0], vec![0, 1, 0], vec![0, 0, 1]];
let mut vec_of_vec = vec![vec![1, 0, 0], vec![0, 1, 0], vec![0, 0, 1]];
function_2d(&mut vec_of_array);
function_2d(&mut array_of_vec);
function_2d(&mut vec_of_vec);

To make it 3d, you add another type parameter:

fn function_3d<V: AsMut<[i32]>, P: AsMut<[V]>>(array: &mut [P]) {
    array[1].as_mut()[2].as_mut()[0] = 1;
}

is it possible to remove or insert a element from particular position of 2d vector without iterating like in 1d vector

I should note that this is not possible with the AsMut approach, because insertion and removal is only defined for resizable containers like Vec. But based on your original question about array types, I am unsure why you would be interested in removing and inserting elements!

1 Like

You mean like this?

fn produce_vec() -> Vec<i32> {
    vec![1, 2, 3]
}
1 Like

In this case it shows that Rust is a low level language. At the hardware level that Rust is concerned with, the concept of 2d/3d vector doesn’t exist — there’s just no such thing at all. The RAM is 1d, so it’s up to the programmer to figure out mapping between 2d/3d/Nd vector abstraction and the linear RAM.

There are different ways to do this depending on what flexibility and performance you need, for what size. Insertion or removal of elements may be implemented in different ways, meaning different things. Are your dimensions 3x3 or million x million?

In Vec insertion requires copying and moving of all elements later in the vector, which for large vectors or frequent insertions gets really slow.

For multi dimensional vec you probably want setting/replacement, not literal insterion.

If your multi dimensional data is sparse, then even all forms of Vec may be a wrong approach and you may need HashMap<(x,y,z),…> instead.

1 Like

how to make 3d vector in the same way

Well, the most ergonomic way would be the following:

let initial_value = 0;
let width = 5, height = 10, depth = 15;
let myvec = vec![vec![vec![initial_value; depth]; height]; width];

But it depends on what you want to achieve, as this is technically what other languages call a jagged array, so this can have a variety of configurations

Could you explain why? That’s great news, just curious why it should be avoided.

Rust doesn’t allow uninitialised data to exist at any point, which makes creating arrays harder.

Rust can’t implement traits for arrays of arbitrary size yet, so there are plenty of cases where support for arrays is hardcoded up to 32 elements.

Arrays are not properly integrated with iterators. IntoIter is subtly broken. FromIterator is not supported.

It’s not that common to actually, semantically need fixed size. It’s fine for things like a hash function output, but not when you define arbitrary FOO_MAX. There are crates like smallvec and arrayvec if you use an array only because you want to avoid using the heap.

2 Likes

how to increase the depth ,height and width using push function or how to use push and pop function in multi dimensional vector

To increase the size of a vector we use vec.push(x), so in this case we would need to do the following to increase the width (if the vector is stored width, height, depth):

for _ in 0..incrementing_width {
    vec.push(vec![vec![initial_value; depth]; height]);
}

That will just push a new element onto the outermost vector. To increase height:

for column in &mut vec {
    for _ in 0..incrementing_height {
        column.push(vec![initial_value; depth]);
    }
}

And a similar approach for depth:

for column in &mut vec {
    for z_row in column {
        for _ in 0..incrementing_depth {
            z_row.push(initial_value);
        }
    }
}
1 Like