For each element of `list_array[i]`, removed up to `arr_n[i]` occurrences of `element_array[i]`. The type of each **element** in `list_array` must be the same as the type of `element_array`. This function also handles nested arrays ([`arrow::array::ListArray`] of [`arrow::array::ListArray`]s) For example, when called to remove a list array (where each element is a list of int32s, the second argu
(
list_array: &GenericListArray<OffsetSize>,
element_array: &ArrayRef,
arr_n: &[i64],
)
| 375 | /// ) |
| 376 | /// ``` |
| 377 | fn general_remove<OffsetSize: OffsetSizeTrait>( |
| 378 | list_array: &GenericListArray<OffsetSize>, |
| 379 | element_array: &ArrayRef, |
| 380 | arr_n: &[i64], |
| 381 | ) -> Result<ArrayRef> { |
| 382 | let list_field = match list_array.data_type() { |
| 383 | DataType::List(field) | DataType::LargeList(field) => field, |
| 384 | _ => { |
| 385 | return exec_err!( |
| 386 | "Expected List or LargeList data type, got {:?}", |
| 387 | list_array.data_type() |
| 388 | ); |
| 389 | } |
| 390 | }; |
| 391 | let original_data = list_array.values().to_data(); |
| 392 | // Build up the offsets for the final output array |
| 393 | let mut offsets = Vec::<OffsetSize>::with_capacity(arr_n.len() + 1); |
| 394 | offsets.push(OffsetSize::zero()); |
| 395 | |
| 396 | let mut mutable = MutableArrayData::with_capacities( |
| 397 | vec![&original_data], |
| 398 | false, |
| 399 | Capacities::Array(original_data.len()), |
| 400 | ); |
| 401 | |
| 402 | // Pre-compute combined null bitmap |
| 403 | let nulls = NullBuffer::union(list_array.nulls(), element_array.nulls()); |
| 404 | |
| 405 | for (row_index, offset_window) in list_array.offsets().windows(2).enumerate() { |
| 406 | if nulls.as_ref().is_some_and(|nulls| nulls.is_null(row_index)) { |
| 407 | offsets.push(offsets[row_index]); |
| 408 | continue; |
| 409 | } |
| 410 | |
| 411 | let start = offset_window[0].to_usize().unwrap(); |
| 412 | let end = offset_window[1].to_usize().unwrap(); |
| 413 | // n is the number of elements to remove in this row |
| 414 | let n = arr_n[row_index]; |
| 415 | |
| 416 | // compare each element in the list, `false` means the element matches and should be removed |
| 417 | let eq_array = utils::compare_element_to_list( |
| 418 | &list_array.value(row_index), |
| 419 | element_array, |
| 420 | row_index, |
| 421 | false, |
| 422 | )?; |
| 423 | |
| 424 | let num_to_remove = eq_array.false_count(); |
| 425 | |
| 426 | // Fast path: no elements to remove, copy entire row |
| 427 | if num_to_remove == 0 { |
| 428 | mutable.extend(0, start, end); |
| 429 | offsets.push(offsets[row_index] + OffsetSize::usize_as(end - start)); |
| 430 | continue; |
| 431 | } |
| 432 | |
| 433 | // Remove at most `n` matching elements |
| 434 | let max_removals = n.min(num_to_remove as i64); |
nothing calls this directly
no test coverage detected
searching dependent graphs…