Skip to content
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion cpp/src/arrow/array/array_nested.h
Original file line number Diff line number Diff line change
Expand Up @@ -69,9 +69,11 @@ class BaseListArray : public Array {
const TypeClass* list_type() const { return list_type_; }

/// \brief Return array object containing the list's values
///
/// Note that this buffer does not account for any slice offset or length.
std::shared_ptr<Array> values() const { return values_; }

/// Note that this buffer does not account for any slice offset
/// Note that this buffer does not account for any slice offset or length.
std::shared_ptr<Buffer> value_offsets() const { return data_->buffers[1]; }

std::shared_ptr<DataType> value_type() const { return list_type_->value_type(); }
Expand Down
21 changes: 15 additions & 6 deletions python/pyarrow/src/arrow/python/arrow_to_pandas.cc
Original file line number Diff line number Diff line change
Expand Up @@ -738,11 +738,15 @@ Status ConvertListsLike(PandasOptions options, const ChunkedArray& data,
ArrayVector value_arrays;
for (int c = 0; c < data.num_chunks(); c++) {
const auto& arr = checked_cast<const ListArrayT&>(*data.chunk(c));
// values() does not account for offsets, so we need to slice into it.
// We can't use Flatten(), because it removes the null values, which we need.
std::shared_ptr<Array> flattened_values = arr.values()->Slice(
arr.value_offset(0), arr.value_offset(arr.length()) - arr.value_offset(0));
if (arr.value_type()->id() == Type::EXTENSION) {
const auto& arr_ext = checked_cast<const ExtensionArray&>(*arr.values());
const auto& arr_ext = checked_cast<const ExtensionArray&>(*flattened_values);
value_arrays.emplace_back(arr_ext.storage());
} else {
value_arrays.emplace_back(arr.values());
value_arrays.emplace_back(flattened_values);
}
}

Expand Down Expand Up @@ -772,8 +776,12 @@ Status ConvertListsLike(PandasOptions options, const ChunkedArray& data,
Py_INCREF(Py_None);
*out_values = Py_None;
} else {
OwnedRef start(PyLong_FromLongLong(arr.value_offset(i) + chunk_offset));
OwnedRef end(PyLong_FromLongLong(arr.value_offset(i + 1) + chunk_offset));
// Need to subtract value_offset(0) since the original chunk might be a slice
// into another array.
OwnedRef start(PyLong_FromLongLong(arr.value_offset(i) + chunk_offset -
arr.value_offset(0)));
OwnedRef end(PyLong_FromLongLong(arr.value_offset(i + 1) + chunk_offset -
arr.value_offset(0)));
OwnedRef slice(PySlice_New(start.obj(), end.obj(), nullptr));

if (ARROW_PREDICT_FALSE(slice.obj() == nullptr)) {
Expand All @@ -791,7 +799,7 @@ Status ConvertListsLike(PandasOptions options, const ChunkedArray& data,
}
RETURN_IF_PYERROR();

chunk_offset += arr.values()->length();
chunk_offset += arr.value_offset(arr.length()) - arr.value_offset(0);
}

return Status::OK();
Expand Down Expand Up @@ -1083,7 +1091,8 @@ struct ObjectWriterVisitor {
OwnedRef keywords(PyDict_New());
PyDict_SetItemString(keywords.obj(), "tzinfo", PyDateTime_TimeZone_UTC);
OwnedRef naive_datetime_replace(PyObject_GetAttrString(naive_datetime, "replace"));
OwnedRef datetime_utc(PyObject_Call(naive_datetime_replace.obj(), args.obj(), keywords.obj()));
OwnedRef datetime_utc(
PyObject_Call(naive_datetime_replace.obj(), args.obj(), keywords.obj()));
// second step: adjust the datetime to tzinfo timezone (astimezone method)
*out = PyObject_CallMethod(datetime_utc.obj(), "astimezone", "O", tzinfo.obj());

Expand Down
24 changes: 24 additions & 0 deletions python/pyarrow/tests/test_pandas.py
Original file line number Diff line number Diff line change
Expand Up @@ -4513,3 +4513,27 @@ def test_does_not_mutate_timedelta_nested():
df = table.to_pandas()

assert df["timedelta_2"][0].to_pytimedelta() == timedelta_2[0]


def test_list_no_duplicate_base():

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is a TestConvertListTypes class that groups some list type related tests, maybe can move this somewhere there.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can move it there.

# ARROW-18400
arr = pa.array([[1, 2], [3, 4, 5], [6], [7, 8]])
chunked_arr = pa.chunked_array([arr.slice(0, 2), arr.slice(2, 1)])

np_arr = chunked_arr.to_numpy()

expected = np.array([[1, 2], [3, 4, 5], [6]], dtype="object")
for left, right in zip(np_arr, expected):
npt.assert_array_equal(left, right)

expected_base = np.array([[1, 2, 3, 4, 5, 6]], dtype="object")
npt.assert_array_equal(np_arr[0].base, expected_base)

np_arr_sliced = chunked_arr.slice(1, 3).to_numpy()

expected = np.array([[3, 4, 5], [6]], dtype="object")
for left, right in zip(np_arr_sliced, expected):
npt.assert_array_equal(left, right)

expected_base = np.array([[3, 4, 5, 6]], dtype="object")
npt.assert_array_equal(np_arr_sliced[0].base, expected_base)