arr_rs/core/operations/indexing.rs
1use crate::{
2 core::prelude::*,
3 errors::prelude::*,
4 extensions::prelude::*,
5};
6
7/// `ArrayTrait` - Array Indexing functions
8pub trait ArrayIndexing<T: ArrayElement> where Self: Sized + Clone {
9
10 /// Return an index of element at the given coordinates
11 ///
12 /// # Arguments
13 ///
14 /// * `coords` - vector representing the coordinates of the element in array
15 ///
16 /// # Examples
17 ///
18 /// ```
19 /// use arr_rs::prelude::*;
20 ///
21 /// let arr: Array<i32> = Array::new(vec![1,2,3,4,5,6,7,8], vec![2, 2, 2]).unwrap();
22 ///
23 /// let idx_1 = arr.index_at(&[0, 0, 0]).unwrap();
24 /// assert_eq!(0, idx_1);
25 ///
26 /// let idx_2 = arr.index_at(&[1, 0, 1]).unwrap();
27 /// assert_eq!(5, idx_2);
28 ///
29 /// let idx_3 = arr.index_at(&[1, 1, 1]).unwrap();
30 /// assert_eq!(7, idx_3);
31 /// ```
32 ///
33 /// # Errors
34 ///
35 /// may returns `ArrayError`
36 fn index_at(&self, coords: &[usize]) -> Result<usize, ArrayError>;
37
38 /// Return coordinates at the given index of element
39 ///
40 /// # Arguments
41 ///
42 /// * `index` - index of element in flattened array
43 ///
44 /// # Examples
45 ///
46 /// ```
47 /// use arr_rs::prelude::*;
48 ///
49 /// let arr: Array<i32> = Array::new(vec![1,2,3,4,5,6,7,8], vec![2, 2, 2]).unwrap();
50 ///
51 /// let coord_1 = arr.index_to_coord(0).unwrap();
52 /// assert_eq!(vec![0, 0, 0], coord_1);
53 ///
54 /// let coord_2 = arr.index_to_coord(5).unwrap();
55 /// assert_eq!(vec![1, 0, 1], coord_2);
56 ///
57 /// let coord_3 = arr.index_to_coord(7).unwrap();
58 /// assert_eq!(vec![1, 1, 1], coord_3);
59 /// ```
60 ///
61 /// # Errors
62 ///
63 /// may returns `ArrayError`
64 fn index_to_coord(&self, idx: usize) -> Result<Vec<usize>, ArrayError>;
65
66 /// Return an index of element at the given coordinates
67 ///
68 /// # Arguments
69 ///
70 /// * `coords` - vector representing the coordinates of the element in array
71 ///
72 /// # Examples
73 ///
74 /// ```
75 /// use arr_rs::prelude::*;
76 ///
77 /// let arr: Array<i32> = Array::new(vec![1,2,3,4,5,6,7,8], vec![2, 2, 2]).unwrap();
78 ///
79 /// let at_1 = arr.at(&[0, 0, 0]).unwrap();
80 /// assert_eq!(1, at_1);
81 ///
82 /// let at_2 = arr.at(&[1, 0, 1]).unwrap();
83 /// assert_eq!(6, at_2);
84 ///
85 /// let at_3 = arr.at(&[1, 1, 1]).unwrap();
86 /// assert_eq!(8, at_3);
87 /// ```
88 ///
89 /// # Errors
90 ///
91 /// may returns `ArrayError`
92 fn at(&self, coords: &[usize]) -> Result<T, ArrayError>;
93
94 /// Return a subarray of provided range
95 ///
96 /// # Arguments
97 ///
98 /// * `range` - starting and ending indices of elements to include in the subarray
99 ///
100 /// # Examples
101 ///
102 /// ```
103 /// use arr_rs::prelude::*;
104 ///
105 /// let arr = Array::<i32>::flat(vec![1, 2, 3, 4, 5, 6, 7, 8]).unwrap();
106 /// let expected = Array::<i32>::flat(vec![1, 2, 3, 4]).unwrap();
107 /// assert_eq!(expected, arr.slice(0..4).unwrap());
108 ///
109 /// let arr = Array::<i32>::new(vec![1, 2, 3, 4, 5, 6, 7, 8], vec![2, 4]).unwrap();
110 /// let expected = Array::<i32>::flat(vec![1, 2, 3, 4]).unwrap();
111 /// assert_eq!(expected, arr.slice(0..1).unwrap());
112 /// ```
113 ///
114 /// # Errors
115 ///
116 /// may returns `ArrayError`
117 fn slice(&self, range: std::ops::Range<usize>) -> Result<Array<T>, ArrayError>;
118
119 /// Return a subarray consisting on values on given indices.
120 ///
121 /// # Arguments
122 ///
123 /// * `indices` - indices which should be included in resulting array
124 ///
125 /// # Examples
126 ///
127 /// ```
128 /// use arr_rs::prelude::*;
129 ///
130 /// let arr = Array::<i32>::flat(vec![1, 2, 3, 4, 5, 6, 7, 8]).unwrap();
131 ///
132 /// let expected = Array::<i32>::flat(vec![3, 5, 7]).unwrap();
133 /// let slice_1 = arr.indices_at(&[2, 4, 6]).unwrap();
134 /// assert_eq!(format!("{expected}"), format!("{slice_1}"));
135 ///
136 /// let expected = Array::<i32>::flat(vec![4, 5, 3, 8, 6, 7, 1, 2]).unwrap();
137 /// let slice_1 = arr.indices_at(&[3, 4, 2, 7, 5, 6, 0, 1]).unwrap();
138 /// assert_eq!(format!("{expected}"), format!("{slice_1}"));
139 /// ```
140 ///
141 /// # Errors
142 ///
143 /// may returns `ArrayError`
144 fn indices_at(&self, indices: &[usize]) -> Result<Array<T>, ArrayError>;
145}
146
147impl <T: ArrayElement> ArrayIndexing<T> for Array<T> {
148
149 fn index_at(&self, coords: &[usize]) -> Result<usize, ArrayError> {
150 if self.shape.len() != coords.len() {
151 Err(ArrayError::ParameterError { param: "coords", message: "length must match array dimension", })
152 } else if coords.iter().enumerate().any(|(i, _)| coords[i] >= self.shape[i]) {
153 Err(ArrayError::ParameterError { param: "coords", message: "value must match array shape", })
154 } else {
155 let result = self.shape.iter().enumerate().rev().fold((0, 1), |(mut index, mut stride), (i, &dim)| {
156 index += coords[i] * stride;
157 stride *= dim;
158 (index, stride)
159 }).0;
160 Ok(result)
161 }
162 }
163
164 fn index_to_coord(&self, idx: usize) -> Result<Vec<usize>, ArrayError> {
165 if idx >= self.len()? {
166 Err(ArrayError::ParameterError { param: "idx", message: "index must be smaller than array length", })
167 } else {
168 let result = self.shape.iter().rev().fold((idx, Vec::new()), |(ri, mut coords), &dim| {
169 coords.push(ri % dim);
170 (ri / dim, coords)
171 }).1.into_iter().rev().collect();
172 Ok(result)
173 }
174 }
175
176 fn at(&self, coords: &[usize]) -> Result<T, ArrayError> {
177 match self.index_at(coords) {
178 Ok(idx) => Ok(self.elements[idx].clone()),
179 Err(e) => Err(e),
180 }
181 }
182
183 fn slice(&self, range: std::ops::Range<usize>) -> Result<Self, ArrayError> {
184 if !(range.start <= range.end && range.end <= self.elements.len()) {
185 return Err(ArrayError::OutOfBounds { value: "slice range" })
186 }
187
188 if self.shape.len() == 1 {
189 Self::flat(self.elements[range].into())
190 } else if range.len() >= self.shape[0] {
191 Ok(self.clone())
192 } else {
193 let new_shape =
194 if range.len() > 1 { vec![range.len()].into_iter().chain(self.shape[1..].iter().copied()).collect() }
195 else { self.shape[1..].to_vec() };
196
197 let items: usize = new_shape.iter().product();
198 let stride = items / new_shape[0];
199 let start_index = new_shape[0] * range.start;
200
201 let mut new_elements = Vec::with_capacity(items);
202 (start_index..start_index + items).step_by(stride).for_each(|idx| {
203 new_elements.extend_from_slice(&self.elements[idx..idx + stride]);
204 });
205 Self::new(new_elements, new_shape)
206 }
207 }
208
209 fn indices_at(&self, indices: &[usize]) -> Result<Self, ArrayError> {
210 if self.ndim()? == 1 {
211 for &i in indices {
212 if i >= self.len()? { return Err(ArrayError::OutOfBounds { value: "indices" }) }
213 }
214 indices.iter()
215 .map(|&i| self[i].clone())
216 .collect::<Vec<T>>()
217 .to_array()
218 } else {
219 let arrs = self.split_axis(0)?;
220 for &i in indices {
221 if i >= arrs.len() { return Err(ArrayError::OutOfBounds { value: "indices" }) }
222 }
223 let new_shape = self.get_shape()?.update_at(0, indices.len());
224 indices.iter()
225 .flat_map(|&i| arrs[i].clone())
226 .collect::<Vec<T>>()
227 .to_array()
228 .reshape(&new_shape)
229 }
230 }
231}
232
233impl <T: ArrayElement> ArrayIndexing<T> for Result<Array<T>, ArrayError> {
234
235 fn index_at(&self, coords: &[usize]) -> Result<usize, ArrayError> {
236 self.clone()?.index_at(coords)
237 }
238
239 fn index_to_coord(&self, idx: usize) -> Result<Vec<usize>, ArrayError> {
240 self.clone()?.index_to_coord(idx)
241 }
242
243 fn at(&self, coords: &[usize]) -> Result<T, ArrayError> {
244 self.clone()?.at(coords)
245 }
246
247 fn slice(&self, range: std::ops::Range<usize>) -> Self {
248 self.clone()?.slice(range)
249 }
250
251 fn indices_at(&self, indices: &[usize]) -> Self {
252 self.clone()?.indices_at(indices)
253 }
254}