Skip to content

Commit e188b4b

Browse files
Make VariantArray iterable
1 parent 77ca6dc commit e188b4b

File tree

1 file changed

+184
-0
lines changed

1 file changed

+184
-0
lines changed

parquet-variant-compute/src/variant_array.rs

Lines changed: 184 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -422,6 +422,11 @@ impl VariantArray {
422422
pub fn is_valid(&self, index: usize) -> bool {
423423
!self.is_null(index)
424424
}
425+
426+
/// Returns an iterator over the values in this array
427+
pub fn iter(&self) -> VariantArrayIter<'_> {
428+
VariantArrayIter::new(self)
429+
}
425430
}
426431

427432
impl From<VariantArray> for StructArray {
@@ -436,6 +441,99 @@ impl From<VariantArray> for ArrayRef {
436441
}
437442
}
438443

444+
/// An iterator over [`VariantArray`]
445+
///
446+
/// This iterator returns `Option<Option<Variant<'a, 'a>>>` where:
447+
/// - `None` indicates the end of iteration
448+
/// - `Some(None)` indicates a null value at this position
449+
/// - `Some(Some(variant))` indicates a valid variant value
450+
///
451+
/// # Example
452+
///
453+
/// ```
454+
/// # use parquet_variant::Variant;
455+
/// # use parquet_variant_compute::VariantArrayBuilder;
456+
/// let mut builder = VariantArrayBuilder::new(10);
457+
/// builder.append_variant(Variant::from(42));
458+
/// builder.append_null();
459+
/// builder.append_variant(Variant::from("hello"));
460+
/// let array = builder.build();
461+
///
462+
/// let values = array.iter().collect::<Vec<_>>();
463+
/// assert_eq!(values.len(), 3);
464+
/// assert_eq!(values[0], Some(Variant::from(42)));
465+
/// assert_eq!(values[1], None);
466+
/// assert_eq!(values[2], Some(Variant::from("hello")));
467+
/// ```
468+
#[derive(Debug)]
469+
pub struct VariantArrayIter<'a> {
470+
array: &'a VariantArray,
471+
head_i: usize,
472+
tail_i: usize,
473+
}
474+
475+
impl<'a> VariantArrayIter<'a> {
476+
/// Creates a new iterator over the given [`VariantArray`]
477+
pub fn new(array: &'a VariantArray) -> Self {
478+
Self {
479+
array,
480+
head_i: 0,
481+
tail_i: array.len(),
482+
}
483+
}
484+
485+
/// Helper method to check if the value at the given index is null
486+
#[inline]
487+
fn is_null(&self, idx: usize) -> bool {
488+
self.array.is_null(idx)
489+
}
490+
}
491+
492+
impl<'a> Iterator for VariantArrayIter<'a> {
493+
type Item = Option<Variant<'a, 'a>>;
494+
495+
#[inline]
496+
fn next(&mut self) -> Option<Self::Item> {
497+
if self.head_i == self.tail_i {
498+
return None;
499+
}
500+
501+
let out = if self.is_null(self.head_i) {
502+
Some(None)
503+
} else {
504+
Some(Some(self.array.value(self.head_i)))
505+
};
506+
507+
self.head_i += 1;
508+
509+
out
510+
}
511+
512+
fn size_hint(&self) -> (usize, Option<usize>) {
513+
let remainder = self.tail_i - self.head_i;
514+
515+
(remainder, Some(remainder))
516+
}
517+
}
518+
519+
impl<'a> DoubleEndedIterator for VariantArrayIter<'a> {
520+
fn next_back(&mut self) -> Option<Self::Item> {
521+
if self.head_i == self.tail_i {
522+
return None;
523+
}
524+
525+
self.tail_i -= 1;
526+
527+
if self.is_null(self.tail_i) {
528+
Some(None)
529+
} else {
530+
Some(Some(self.array.value(self.tail_i)))
531+
}
532+
}
533+
}
534+
535+
impl<'a> ExactSizeIterator for VariantArrayIter<'a> {}
536+
439537
/// One shredded field of a partially or prefectly shredded variant. For example, suppose the
440538
/// shredding schema for variant `v` treats it as an object with a single field `a`, where `a` is
441539
/// itself a struct with the single field `b` of type INT. Then the physical layout of the column
@@ -1062,6 +1160,8 @@ fn canonicalize_and_verify_field(field: &Arc<Field>) -> Result<Cow<'_, Arc<Field
10621160

10631161
#[cfg(test)]
10641162
mod test {
1163+
use crate::VariantArrayBuilder;
1164+
10651165
use super::*;
10661166
use arrow::array::{BinaryViewArray, Int32Array};
10671167
use arrow_schema::{Field, Fields};
@@ -1244,4 +1344,88 @@ mod test {
12441344
}
12451345
));
12461346
}
1347+
1348+
#[test]
1349+
fn test_variant_array_iterable() {
1350+
let mut b = VariantArrayBuilder::new(6);
1351+
1352+
b.append_null();
1353+
b.append_variant(Variant::from(1_i8));
1354+
b.append_variant(Variant::Null);
1355+
b.append_variant(Variant::from(2_i32));
1356+
b.append_variant(Variant::from(3_i64));
1357+
b.append_null();
1358+
1359+
let v = b.build();
1360+
1361+
let variants = v.iter().collect::<Vec<_>>();
1362+
1363+
assert_eq!(
1364+
variants,
1365+
vec![
1366+
None,
1367+
Some(Variant::Int8(1)),
1368+
Some(Variant::Null),
1369+
Some(Variant::Int32(2)),
1370+
Some(Variant::Int64(3)),
1371+
None,
1372+
]
1373+
);
1374+
}
1375+
1376+
#[test]
1377+
fn test_variant_array_iter_double_ended() {
1378+
let mut b = VariantArrayBuilder::new(5);
1379+
1380+
b.append_variant(Variant::from(0_i32));
1381+
b.append_null();
1382+
b.append_variant(Variant::from(2_i32));
1383+
b.append_null();
1384+
b.append_variant(Variant::from(4_i32));
1385+
1386+
let array = b.build();
1387+
let mut iter = array.iter();
1388+
1389+
assert_eq!(iter.next(), Some(Some(Variant::from(0_i32))));
1390+
assert_eq!(iter.next(), Some(None));
1391+
1392+
assert_eq!(iter.next_back(), Some(Some(Variant::from(4_i32))));
1393+
assert_eq!(iter.next_back(), Some(None));
1394+
assert_eq!(iter.next_back(), Some(Some(Variant::from(2_i32))));
1395+
1396+
assert_eq!(iter.next_back(), None);
1397+
assert_eq!(iter.next(), None);
1398+
}
1399+
1400+
#[test]
1401+
fn test_variant_array_iter_reverse() {
1402+
let mut b = VariantArrayBuilder::new(5);
1403+
1404+
b.append_variant(Variant::from("a"));
1405+
b.append_null();
1406+
b.append_variant(Variant::from("aaa"));
1407+
b.append_null();
1408+
b.append_variant(Variant::from("aaaaa"));
1409+
1410+
let array = b.build();
1411+
1412+
let result: Vec<_> = array.iter().rev().collect();
1413+
assert_eq!(
1414+
result,
1415+
vec![
1416+
Some(Variant::from("aaaaa")),
1417+
None,
1418+
Some(Variant::from("aaa")),
1419+
None,
1420+
Some(Variant::from("a")),
1421+
]
1422+
);
1423+
}
1424+
1425+
#[test]
1426+
fn test_variant_array_iter_empty() {
1427+
let v = VariantArrayBuilder::new(0).build();
1428+
let mut i = v.iter();
1429+
assert!(i.next().is_none());
1430+
}
12471431
}

0 commit comments

Comments
 (0)