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>,
)
| 382 | /// direction and null ordering are baked into the encoding), and materialize |
| 383 | /// the result with a single `take()`. |
| 384 | fn 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, |
no test coverage detected
searching dependent graphs…