1use vortex_array::ArrayRef;
5use vortex_array::ArrayView;
6use vortex_array::ExecutionCtx;
7use vortex_array::IntoArray;
8use vortex_array::arrays::dict::TakeExecute;
9use vortex_error::VortexResult;
10
11use crate::ConstantArray;
12use crate::Sparse;
13use crate::SparseExt as _;
14impl TakeExecute for Sparse {
15 fn take(
16 array: ArrayView<'_, Self>,
17 indices: &ArrayRef,
18 ctx: &mut ExecutionCtx,
19 ) -> VortexResult<Option<ArrayRef>> {
20 let patches_take = if array.fill_scalar().is_null() {
21 array.patches().take(indices, ctx)?
22 } else {
23 array.patches().take_with_nulls(indices, ctx)?
24 };
25
26 let Some(new_patches) = patches_take else {
27 let result_fill_scalar = array.fill_scalar().cast(
28 &array
29 .dtype()
30 .union_nullability(indices.dtype().nullability()),
31 )?;
32 return Ok(Some(
33 ConstantArray::new(result_fill_scalar, indices.len()).into_array(),
34 ));
35 };
36
37 if new_patches.array_len() == new_patches.values().len() {
39 return Ok(Some(new_patches.into_values()));
40 }
41
42 Ok(Some(
43 Sparse::try_new_from_patches(
44 new_patches,
45 array.fill_scalar().cast(
46 &array
47 .dtype()
48 .union_nullability(indices.dtype().nullability()),
49 )?,
50 )?
51 .into_array(),
52 ))
53 }
54}
55
56#[cfg(test)]
57mod test {
58 use std::sync::LazyLock;
59
60 use rstest::rstest;
61 use vortex_array::ArrayRef;
62 use vortex_array::IntoArray;
63 use vortex_array::VortexSessionExecute;
64 use vortex_array::arrays::ConstantArray;
65 use vortex_array::arrays::PrimitiveArray;
66 use vortex_array::assert_arrays_eq;
67 use vortex_array::dtype::Nullability;
68 use vortex_array::scalar::Scalar;
69 use vortex_array::validity::Validity;
70 use vortex_buffer::buffer;
71 use vortex_session::VortexSession;
72
73 use crate::Sparse;
74 use crate::SparseArray;
75
76 static SESSION: LazyLock<VortexSession> = LazyLock::new(|| {
77 let session = vortex_array::array_session();
78 crate::initialize(&session);
79 session
80 });
81
82 fn test_array_fill_value() -> Scalar {
83 Scalar::null_native::<f64>()
85 }
86
87 fn sparse_array() -> ArrayRef {
88 Sparse::try_new(
89 buffer![0u64, 37, 47, 99].into_array(),
90 PrimitiveArray::new(buffer![1.23f64, 0.47, 9.99, 3.5], Validity::AllValid).into_array(),
91 100,
92 test_array_fill_value(),
93 )
94 .unwrap()
95 .into_array()
96 }
97
98 #[test]
99 fn take_with_non_zero_offset() {
100 let sparse = sparse_array();
101 let sparse = sparse.slice(30..40).unwrap();
102 let taken = sparse.take(buffer![6, 7, 8].into_array()).unwrap();
103 let expected = PrimitiveArray::from_option_iter([Option::<f64>::None, Some(0.47), None]);
104 assert_arrays_eq!(
105 taken,
106 expected.into_array(),
107 &mut SESSION.create_execution_ctx()
108 );
109 }
110
111 #[test]
112 fn sparse_take() {
113 let sparse = sparse_array();
114 let taken = sparse.take(buffer![0, 47, 47, 0, 99].into_array()).unwrap();
115 let expected = PrimitiveArray::from_option_iter([
116 Some(1.23f64),
117 Some(9.99),
118 Some(9.99),
119 Some(1.23),
120 Some(3.5),
121 ]);
122 assert_arrays_eq!(
123 taken,
124 expected.into_array(),
125 &mut SESSION.create_execution_ctx()
126 );
127 }
128
129 #[test]
130 fn nonexistent_take() {
131 let sparse = sparse_array();
132 let taken = sparse.take(buffer![69].into_array()).unwrap();
133 let expected = ConstantArray::new(test_array_fill_value(), 1).into_array();
134 assert_arrays_eq!(taken, expected, &mut SESSION.create_execution_ctx());
135 }
136
137 #[test]
138 fn ordered_take() {
139 let sparse = sparse_array();
140 let taken = sparse.take(buffer![69, 37].into_array()).unwrap();
142 let expected = PrimitiveArray::from_option_iter([Option::<f64>::None, Some(0.47f64)]);
144 assert_arrays_eq!(
145 taken,
146 expected.into_array(),
147 &mut SESSION.create_execution_ctx()
148 );
149 }
150
151 #[test]
152 fn nullable_take() {
153 let arr = Sparse::try_new(
154 buffer![1u32].into_array(),
155 buffer![10].into_array(),
156 10,
157 Scalar::primitive(1, Nullability::NonNullable),
158 )
159 .unwrap();
160
161 let taken = arr
162 .take(
163 PrimitiveArray::from_option_iter([Some(2u32), Some(1u32), Option::<u32>::None])
164 .into_array(),
165 )
166 .unwrap();
167
168 let expected = PrimitiveArray::from_option_iter([Some(1), Some(10), Option::<i32>::None]);
169 assert_arrays_eq!(
170 taken,
171 expected.into_array(),
172 &mut SESSION.create_execution_ctx()
173 );
174 }
175
176 #[test]
177 fn nullable_take_with_many_patches() {
178 let arr = Sparse::try_new(
179 buffer![1u32, 3, 7, 8, 9].into_array(),
180 buffer![10, 8, 3, 2, 1].into_array(),
181 10,
182 Scalar::primitive(1, Nullability::NonNullable),
183 )
184 .unwrap();
185
186 let taken = arr
187 .take(
188 PrimitiveArray::from_option_iter([Some(2u32), Some(1u32), Option::<u32>::None])
189 .into_array(),
190 )
191 .unwrap();
192
193 let expected = PrimitiveArray::from_option_iter([Some(1), Some(10), Option::<i32>::None]);
194 assert_arrays_eq!(
195 taken,
196 expected.into_array(),
197 &mut SESSION.create_execution_ctx()
198 );
199 }
200
201 #[rstest]
202 #[case(Sparse::try_new(
203 buffer![0u64, 37, 47, 99].into_array(),
204 PrimitiveArray::new(buffer![1.23f64, 0.47, 9.99, 3.5], Validity::AllValid).into_array(),
205 100,
206 Scalar::null_native::<f64>(),
207 ).unwrap())]
208 #[case(Sparse::try_new(
209 buffer![1u32, 3, 7, 8, 9].into_array(),
210 buffer![10, 8, 3, 2, 1].into_array(),
211 10,
212 Scalar::from(0i32),
213 ).unwrap())]
214 #[case({
215 let nullable_values = PrimitiveArray::from_option_iter([Some(100i64), None, Some(300)]);
216 Sparse::try_new(
217 buffer![2u64, 4, 6].into_array(),
218 nullable_values.into_array(),
219 10,
220 Scalar::null_native::<i64>(),
221 ).unwrap()
222 })]
223 #[case(Sparse::try_new(
224 buffer![5u64].into_array(),
225 buffer![999i32].into_array(),
226 20,
227 Scalar::from(-1i32),
228 ).unwrap())]
229 fn test_take_sparse_conformance(#[case] sparse: SparseArray) {
230 use vortex_array::compute::conformance::take::test_take_conformance;
231 test_take_conformance(&sparse.into_array());
232 }
233}