| 757 | |
| 758 | template <typename T> |
| 759 | enable_if_list_like<T, Status> ConvertListsLike(PandasOptions options, |
| 760 | const ChunkedArray& data, |
| 761 | PyObject** out_values) { |
| 762 | using ListArrayT = typename TypeTraits<T>::ArrayType; |
| 763 | // Get column of underlying value arrays |
| 764 | ArrayVector value_arrays; |
| 765 | for (int c = 0; c < data.num_chunks(); c++) { |
| 766 | const auto& arr = checked_cast<const ListArrayT&>(*data.chunk(c)); |
| 767 | // values() does not account for offsets, so we need to slice into it. |
| 768 | // We can't use Flatten(), because it removes the values behind a null list |
| 769 | // value, and that makes the offsets into original list values and our |
| 770 | // flattened_values array different. |
| 771 | std::shared_ptr<Array> flattened_values = arr.values()->Slice( |
| 772 | arr.value_offset(0), arr.value_offset(arr.length()) - arr.value_offset(0)); |
| 773 | if (arr.value_type()->id() == Type::EXTENSION) { |
| 774 | const auto& arr_ext = checked_cast<const ExtensionArray&>(*flattened_values); |
| 775 | value_arrays.emplace_back(arr_ext.storage()); |
| 776 | } else { |
| 777 | value_arrays.emplace_back(flattened_values); |
| 778 | } |
| 779 | } |
| 780 | |
| 781 | using ListArrayType = typename ListArrayT::TypeClass; |
| 782 | const auto& list_type = checked_cast<const ListArrayType&>(*data.type()); |
| 783 | auto value_type = list_type.value_type(); |
| 784 | if (value_type->id() == Type::EXTENSION) { |
| 785 | value_type = checked_cast<const ExtensionType&>(*value_type).storage_type(); |
| 786 | } |
| 787 | |
| 788 | auto flat_column = std::make_shared<ChunkedArray>(value_arrays, value_type); |
| 789 | |
| 790 | options = MakeInnerOptions(std::move(options)); |
| 791 | |
| 792 | OwnedRefNoGIL owned_numpy_array; |
| 793 | RETURN_NOT_OK(ConvertChunkedArrayToPandas(options, flat_column, nullptr, |
| 794 | owned_numpy_array.ref())); |
| 795 | PyObject* numpy_array = owned_numpy_array.obj(); |
| 796 | ARROW_DCHECK(PyArray_Check(numpy_array)); |
| 797 | |
| 798 | int64_t chunk_offset = 0; |
| 799 | for (int c = 0; c < data.num_chunks(); c++) { |
| 800 | const auto& arr = checked_cast<const ListArrayT&>(*data.chunk(c)); |
| 801 | const bool has_nulls = data.null_count() > 0; |
| 802 | for (int64_t i = 0; i < arr.length(); ++i) { |
| 803 | if (has_nulls && arr.IsNull(i)) { |
| 804 | Py_INCREF(Py_None); |
| 805 | *out_values = Py_None; |
| 806 | } else { |
| 807 | // Need to subtract value_offset(0) since the original chunk might be a slice |
| 808 | // into another array. |
| 809 | OwnedRef start(PyLong_FromLongLong(arr.value_offset(i) + chunk_offset - |
| 810 | arr.value_offset(0))); |
| 811 | OwnedRef end(PyLong_FromLongLong(arr.value_offset(i + 1) + chunk_offset - |
| 812 | arr.value_offset(0))); |
| 813 | OwnedRef slice(PySlice_New(start.obj(), end.obj(), nullptr)); |
| 814 | |
| 815 | if (ARROW_PREDICT_FALSE(slice.obj() == nullptr)) { |
| 816 | // Fall out of loop, will return from RETURN_IF_PYERROR |
nothing calls this directly
no test coverage detected