MCPcopy Create free account
hub / github.com/apache/datafusion / general_array_distinct

Function general_array_distinct

datafusion/functions-nested/src/set_ops.rs:547–618  ·  view source on GitHub ↗
(
    array: &GenericListArray<OffsetSize>,
    field: &FieldRef,
)

Source from the content-addressed store, hash-verified

545}
546
547fn general_array_distinct<OffsetSize: OffsetSizeTrait>(
548 array: &GenericListArray<OffsetSize>,
549 field: &FieldRef,
550) -> Result<ArrayRef> {
551 if array.is_empty() {
552 return Ok(Arc::new(array.clone()) as ArrayRef);
553 }
554 let value_offsets = array.value_offsets();
555 let dt = array.value_type();
556 let mut offsets = Vec::with_capacity(array.len() + 1);
557 offsets.push(OffsetSize::usize_as(0));
558
559 let converter = RowConverter::new(vec![SortField::new(dt.clone())])?;
560
561 // Only convert the visible portion of the values array. For sliced
562 // ListArrays, values() returns the full underlying array but only
563 // elements between the first and last offset are referenced.
564 let first_offset = value_offsets[0].as_usize();
565 let visible_len = value_offsets[array.len()].as_usize() - first_offset;
566 let rows =
567 converter.convert_columns(&[array.values().slice(first_offset, visible_len)])?;
568
569 let mut indices: Vec<usize> = Vec::with_capacity(rows.num_rows());
570 let mut seen = HashSet::new();
571 for i in 0..array.len() {
572 let last_offset = *offsets.last().unwrap();
573
574 // Null list entries produce no output; just carry forward the offset.
575 if array.is_null(i) {
576 offsets.push(last_offset);
577 continue;
578 }
579
580 let start = value_offsets[i].as_usize() - first_offset;
581 let end = value_offsets[i + 1].as_usize() - first_offset;
582 seen.clear();
583 seen.reserve(end - start);
584
585 // Walk the sub-array and keep only the first occurrence of each value.
586 for idx in start..end {
587 let row = rows.row(idx);
588 if seen.insert(row) {
589 indices.push(idx + first_offset);
590 }
591 }
592 offsets.push(last_offset + OffsetSize::usize_as(seen.len()));
593 }
594
595 // Gather distinct values in a single pass, using the computed `indices`.
596 // Indices are absolute positions in array.values() (first_offset was added
597 // back when collecting them), so we can take directly from the full values.
598 // Use UInt64Array for LargeList to support values arrays exceeding u32::MAX.
599 let final_values = if indices.is_empty() {
600 new_empty_array(&dt)
601 } else if OffsetSize::IS_LARGE {
602 let indices =
603 UInt64Array::from(indices.into_iter().map(|i| i as u64).collect::<Vec<_>>());
604 take(array.values().as_ref(), &indices, None)?

Callers 1

array_distinct_innerFunction · 0.85

Calls 15

newFunction · 0.85
value_offsetsMethod · 0.80
value_typeMethod · 0.80
sliceMethod · 0.80
lastMethod · 0.80
reserveMethod · 0.80
rowMethod · 0.80
is_emptyMethod · 0.45
cloneMethod · 0.45
lenMethod · 0.45
pushMethod · 0.45
as_usizeMethod · 0.45

Tested by

no test coverage detected

Used in the wild real call sites across dependent graphs

searching dependent graphs…