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

Function array_sort_non_primitive

datafusion/functions-nested/src/sort.rs:384–444  ·  view source on GitHub ↗

Sort a non-pritive-typed ListArray by converting all rows at once using `RowConverter`, and then sort row indices by comparing encoded bytes (sort direction and null ordering are baked into the encoding), and materialize the result with a single `take()`.

(
    list_array: &GenericListArray<OffsetSize>,
    field: FieldRef,
    sort_options: Option<SortOptions>,
)

Source from the content-addressed store, hash-verified

382/// direction and null ordering are baked into the encoding), and materialize
383/// the result with a single `take()`.
384fn array_sort_non_primitive<OffsetSize: OffsetSizeTrait>(
385 list_array: &GenericListArray<OffsetSize>,
386 field: FieldRef,
387 sort_options: Option<SortOptions>,
388) -> Result<ArrayRef> {
389 let row_count = list_array.len();
390 let values = list_array.values();
391 let offsets = list_array.offsets();
392 let values_start = offsets[0].as_usize();
393 let total_values = offsets[row_count].as_usize() - values_start;
394
395 let converter = RowConverter::new(vec![SortField::new_with_options(
396 values.data_type().clone(),
397 sort_options.unwrap_or_default(),
398 )])?;
399 let values_sliced = values.slice(values_start, total_values);
400 let rows = converter.convert_columns(&[Arc::clone(&values_sliced)])?;
401
402 let mut indices: Vec<OffsetSize> = Vec::with_capacity(total_values);
403 let mut new_offsets = Vec::with_capacity(row_count + 1);
404 new_offsets.push(OffsetSize::usize_as(0));
405
406 let mut sort_scratch: Vec<usize> = Vec::new();
407
408 for (row_index, window) in offsets.windows(2).enumerate() {
409 let start = window[0];
410 let end = window[1];
411
412 if list_array.is_null(row_index) {
413 new_offsets.push(new_offsets[row_index]);
414 continue;
415 }
416
417 let len = (end - start).as_usize();
418 let local_start = start.as_usize() - values_start;
419
420 if len <= 1 {
421 indices.extend((local_start..local_start + len).map(OffsetSize::usize_as));
422 } else {
423 sort_scratch.clear();
424 sort_scratch.extend(local_start..local_start + len);
425 sort_scratch.sort_unstable_by(|&a, &b| rows.row(a).cmp(&rows.row(b)));
426 indices.extend(sort_scratch.iter().map(|&i| OffsetSize::usize_as(i)));
427 }
428
429 new_offsets.push(new_offsets[row_index] + (end - start));
430 }
431
432 let sorted_values = if indices.is_empty() {
433 new_empty_array(values.data_type())
434 } else {
435 take_by_indices(&values_sliced, indices)?
436 };
437
438 Ok(Arc::new(GenericListArray::<OffsetSize>::try_new(
439 field,
440 OffsetBuffer::<OffsetSize>::new(new_offsets.into()),
441 sorted_values,

Callers 1

array_sort_genericFunction · 0.85

Calls 15

newFunction · 0.85
take_by_indicesFunction · 0.85
offsetsMethod · 0.80
sliceMethod · 0.80
rowMethod · 0.80
lenMethod · 0.45
valuesMethod · 0.45
as_usizeMethod · 0.45
pushMethod · 0.45
is_nullMethod · 0.45
extendMethod · 0.45
mapMethod · 0.45

Tested by

no test coverage detected

Used in the wild real call sites across dependent graphs

searching dependent graphs…