(
array: &GenericListArray<OffsetSize>,
field: &FieldRef,
)
| 545 | } |
| 546 | |
| 547 | fn 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)? |
no test coverage detected
searching dependent graphs…