rust-ndarray / ndarray

ndarray: an N-dimensional array with array views, multidimensional slicing, and efficient operations
https://docs.rs/ndarray/
Apache License 2.0
3.61k stars 307 forks source link

Index array with another array #1233

Closed danjenson closed 1 year ago

danjenson commented 1 year ago

I have had trouble finding this in the documentation, but in numpy you can do the following:

idx = np.array([3, 1, 2])
values = np.arange(10)
values[idx]  # returns array([3, 1, 2])
let x = values[idx.into()]  // yields a single element
let y = values.slice(idx.into()) // can't convert array into SliceInfo or SliceArg

What is the most idiomatic way to index an ndarray::Array1 with another ndarray::Array1?

mdrokz commented 1 year ago

I have had trouble finding this in the documentation, but in numpy you can do the following:

idx = np.array([3, 1, 2])
values = np.arange(10)
values[idx]  # returns array([3, 1, 2])
let x = values[idx.into()]  // yields a single element
let y = values.slice(idx.into()) // can't convert array into SliceInfo or SliceArg

What is the most idiomatic way to index an ndarray::Array1 with another ndarray::Array1?

im also looking to do the same thing with my project

geo_map[:,:,0] += d1[index_y, index_x] * temp_mask
geo_map[:,:,1] += d2[index_y, index_x] * temp_mask
geo_map[:,:,2] += d3[index_y, index_x] * temp_mask
geo_map[:,:,3] += d4[index_y, index_x] * temp_mask
geo_map[:,:,4] += theta * temp_mask

in python numpy you can do this, any way to do this in rust ?

nilgoyette commented 1 year ago

You might be interested in select. however, as you can see, it asks for a slice if indices, so you might be forced to call as_slice_memory_order, or use a Vec for the array of index.

As for the other question, you might want the documentation and/or the python comparison. It will help you get started. IIRC, you will be forced to put the "left side" in a variable, then do the math. It's something like

let mut lhs = geo_map.slice(s![.., .., 0]);
lhs += d1[(index_y, index_x)] * temp_mask;
mdrokz commented 1 year ago

You might be interested in select. however, as you can see, it asks for a slice if indices, so you might be forced to call as_slice_memory_order, or use a Vec for the array of index.

As for the other question, you might want the documentation and/or the python comparison. It will help you get started. IIRC, you will be forced to put the "left side" in a variable, then do the math. It's something like

let mut lhs = geo_map.slice(s![.., .., 0]);
lhs += d1[(index_y, index_x)] * temp_mask;

Hi, i tried what you suggested in this code


   let x: Array2<f32> = array![[ 0.,  1.,  2.],[ 3.,  4.,  5.],[ 6.,  7.,  8.],[ 9., 10., 11.]];

   let rows = array![[0.,0.],[3.,3.]];

    let cols = array![[0.,2.],[0.,2.]];

    let y = x[(rows,cols)];

but i get this error

error[E0277]: the trait bound `(ArrayBase<OwnedRepr<{float}>, Dim<[usize; 2]>>, ArrayBase<OwnedRepr<{float}>, Dim<[usize; 2]>>): NdIndex<Dim<[usize; 2]>>` is not satisfied
nilgoyette commented 1 year ago

When you wrote d1[index_y, index_x], I though that those were real usize indices. Now I see that they are arrays.

This is not ndarray's way of doing things. Much like panda -> pola-rs (if you know about those libraries), ndarray and pola-rs don't use indexing that way. Of course, they offer other ways of doing things.

In your specific example, you could use it that way

let y = x.slice(s![..;3, ..;2])

You seem to know numpy. In that case, I strongly suggest that you read this document. And then the quickstart tutorial.

mdrokz commented 1 year ago

I see, i read those documents before but i couldnt find a way to do 2d indexing with arrays and the slice method can work but the array i will use will be dynamic and i wont know the static values, so is there anyway to use rows & cols to index the x array without specifying a static value in slice method?

nilgoyette commented 1 year ago

Hum, keep in mind that you can use negative numbers and variables in s!.

In case you have "random" indices, I think you need to code your own solution. Something like

let x = ...
let arr = Array2::from_shape_fn((rows.len(), cols.len()), |(i, j)| x[(rows[i], cols[j])] });

Put it in a function if you need to do it often.

mdrokz commented 1 year ago

Hum, keep in mind that you can use negative numbers and variables in s!.

In case you have "random" indices, I think you need to code your own solution. Something like

let x = ...
let arr = Array2::from_shape_fn((rows.len(), cols.len()), |(i, j)| x[(rows[i], cols[j])] });

Put it in a function if you need to do it often.

Yes that works for me, thank you so much