(
l: &GenericListArray<OffsetSize>,
r: &GenericListArray<OffsetSize>,
field: &FieldRef,
)
| 163 | } |
| 164 | |
| 165 | fn general_except<OffsetSize: OffsetSizeTrait>( |
| 166 | l: &GenericListArray<OffsetSize>, |
| 167 | r: &GenericListArray<OffsetSize>, |
| 168 | field: &FieldRef, |
| 169 | ) -> Result<GenericListArray<OffsetSize>> { |
| 170 | let converter = RowConverter::new(vec![SortField::new(l.value_type())])?; |
| 171 | |
| 172 | // Only convert the visible portion of the values array. For sliced |
| 173 | // ListArrays, values() returns the full underlying array but only |
| 174 | // elements between the first and last offset are referenced. |
| 175 | let l_first = l.offsets()[0].as_usize(); |
| 176 | let l_len = l.offsets()[l.len()].as_usize() - l_first; |
| 177 | let l_values = converter.convert_columns(&[l.values().slice(l_first, l_len)])?; |
| 178 | |
| 179 | let r_first = r.offsets()[0].as_usize(); |
| 180 | let r_len = r.offsets()[r.len()].as_usize() - r_first; |
| 181 | let r_values = converter.convert_columns(&[r.values().slice(r_first, r_len)])?; |
| 182 | |
| 183 | let mut offsets = Vec::<OffsetSize>::with_capacity(l.len() + 1); |
| 184 | offsets.push(OffsetSize::usize_as(0)); |
| 185 | |
| 186 | let mut indices: Vec<usize> = Vec::with_capacity(l_values.num_rows()); |
| 187 | let mut dedup = HashSet::new(); |
| 188 | |
| 189 | let nulls = NullBuffer::union(l.nulls(), r.nulls()); |
| 190 | |
| 191 | let l_offsets_iter = l.offsets().iter().tuple_windows(); |
| 192 | let r_offsets_iter = r.offsets().iter().tuple_windows(); |
| 193 | for (list_index, ((l_start, l_end), (r_start, r_end))) in |
| 194 | l_offsets_iter.zip(r_offsets_iter).enumerate() |
| 195 | { |
| 196 | if nulls |
| 197 | .as_ref() |
| 198 | .is_some_and(|nulls| nulls.is_null(list_index)) |
| 199 | { |
| 200 | offsets.push(OffsetSize::usize_as(indices.len())); |
| 201 | continue; |
| 202 | } |
| 203 | |
| 204 | for element_index in r_start.as_usize() - r_first..r_end.as_usize() - r_first { |
| 205 | let right_row = r_values.row(element_index); |
| 206 | dedup.insert(right_row); |
| 207 | } |
| 208 | for element_index in l_start.as_usize() - l_first..l_end.as_usize() - l_first { |
| 209 | let left_row = l_values.row(element_index); |
| 210 | if dedup.insert(left_row) { |
| 211 | indices.push(element_index + l_first); |
| 212 | } |
| 213 | } |
| 214 | |
| 215 | offsets.push(OffsetSize::usize_as(indices.len())); |
| 216 | dedup.clear(); |
| 217 | } |
| 218 | |
| 219 | // Gather distinct left-side values by index. |
| 220 | // Use UInt64Array for LargeList to support values arrays exceeding u32::MAX. |
| 221 | let values = if indices.is_empty() { |
| 222 | arrow::array::new_empty_array(&l.value_type()) |
nothing calls this directly
no test coverage detected
searching dependent graphs…