Vấn đề ở đây (bạn có thể biết đã nhưng chỉ để lặp lại nó) là list.index
công trình dọc theo dòng:
for idx, item in enumerate(your_list):
if item == wanted_item:
return idx
Dòng if item == wanted_item
là vấn đề, bởi vì nó ngầm chuyển đổi item == wanted_item
để một boolean. Nhưng numpy.ndarray
(trừ khi đó là một vô hướng) làm tăng ValueError
này sau đó:
ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()
Giải pháp 1: bộ chuyển đổi (wrapper mỏng) lớp
Tôi thường sử dụng một wrapper mỏng (bộ chuyển đổi) xung quanh numpy.ndarray
bất cứ khi nào tôi cần phải sử dụng chức năng python như list.index
:
class ArrayWrapper(object):
__slots__ = ["_array"] # minimizes the memory footprint of the class.
def __init__(self, array):
self._array = array
def __eq__(self, other_array):
# array_equal also makes sure the shape is identical!
# If you don't mind broadcasting you can also use
# np.all(self._array == other_array)
return np.array_equal(self._array, other_array)
def __array__(self):
# This makes sure that `np.asarray` works and quite fast.
return self._array
def __repr__(self):
return repr(self._array)
Những giấy gói mỏng đắt hơn so với cách thủ sử dụng một số enumerate
vòng lặp hoặc hiểu nhưng bạn không cần phải r e-thực hiện các chức năng python.Giả sử danh sách chứa chỉ NumPy-mảng (nếu không bạn cần phải làm một số if ... else ...
kiểm tra):
list_of_wrapped_arrays = [ArrayWrapper(arr) for arr in list_of_arrays]
Sau bước này bạn có thể sử dụng tất cả chức năng python của bạn trong danh sách này:
>>> list_of_arrays = [np.ones((3, 3)), np.ones((3)), np.ones((3, 3)) * 2, np.ones((3))]
>>> list_of_wrapped_arrays.index(np.ones((3,3)))
0
>>> list_of_wrapped_arrays.index(np.ones((3)))
1
Những giấy gói là không còn mảng nữa nhưng bạn có các trình bao bọc mỏng nên danh sách bổ sung là khá nhỏ. Vì vậy, tùy thuộc vào nhu cầu của bạn, bạn có thể giữ cho danh sách bọc và danh sách ban đầu và chọn trên đó để làm các hoạt động, ví dụ bạn có thể cũng list.count
các mảng giống hệt bây giờ:
>>> list_of_wrapped_arrays.count(np.ones((3)))
2
hoặc list.remove
:
>>> list_of_wrapped_arrays.remove(np.ones((3)))
>>> list_of_wrapped_arrays
[array([[ 1., 1., 1.],
[ 1., 1., 1.],
[ 1., 1., 1.]]),
array([[ 2., 2., 2.],
[ 2., 2., 2.],
[ 2., 2., 2.]]),
array([ 1., 1., 1.])]
Giải pháp 2: phân lớp và ndarray.view
Cách tiếp cận này sử dụng các lớp con rõ ràng là numpy.array
. Nó có ưu điểm là bạn nhận được tất cả được xây dựng trong mảng chức năng và chỉ sửa đổi các hoạt động yêu cầu (đó sẽ là __eq__
):
class ArrayWrapper(np.ndarray):
def __eq__(self, other_array):
return np.array_equal(self, other_array)
>>> your_list = [np.ones(3), np.ones(3)*2, np.ones(3)*3, np.ones(3)*4]
>>> view_list = [arr.view(ArrayWrapper) for arr in your_list]
>>> view_list.index(np.array([2,2,2]))
1
Một lần nữa bạn nhận được hầu hết các phương pháp danh sách theo cách này: list.remove
, list.count
ngoài list.index
.
Tuy nhiên cách tiếp cận này có thể mang lại hành vi tinh vi nếu một số thao tác sử dụng ngầm sử dụng __eq__
. Bạn luôn có thể giải thích là như mảng NumPy đơn giản bằng cách sử dụng np.asarray
hoặc .view(np.ndarray)
:
>>> view_list[1]
ArrayWrapper([ 2., 2., 2.])
>>> view_list[1].view(np.ndarray)
array([ 2., 2., 2.])
>>> np.asarray(view_list[1])
array([ 2., 2., 2.])
Alternative: Overriding __bool__
(hoặc __nonzero__
cho python 2)
Thay vì sửa chữa các vấn đề trong phương pháp __eq__
bạn có thể cũng ghi đè __bool__
hoặc __nonzero__
:
class ArrayWrapper(np.ndarray):
# This could also be done in the adapter solution.
def __bool__(self):
return bool(np.all(self))
__nonzero__ = __bool__
Một lần nữa điều này làm cho công việc list.index
như dự định:
>>> your_list = [np.ones(3), np.ones(3)*2, np.ones(3)*3, np.ones(3)*4]
>>> view_list = [arr.view(ArrayWrapper) for arr in your_list]
>>> view_list.index(np.array([2,2,2]))
1
Nhưng điều này chắc chắn sẽ sửa đổi nhiều hành vi hơn! Ví dụ:
>>> if ArrayWrapper([1,2,3]):
... print('that was previously impossible!')
that was previously impossible!
Rất rất thú vị. –
Danh sách không đồng nhất chỉ là một ví dụ, hay bạn thực sự có một danh sách với nhiều loại khác nhau trong nó? – mgilson
@mgilson chỉ là ví dụ giả tạo của tôi. Tôi đang làm việc với một danh sách các mảng numpy có kích thước bằng nhau – Lee88