2017-12-01 8 views
0

私は、形状がn×2で長さが2のタプルの配列を持ち、SortedListに転送したいと思います。ですから、長さ2の整数タプルを持つSortedListを作成することです。n×2のnumpy配列からSortedLIstを取り出す

問題は、SortedListのコンストラクタが各エントリの真理値をチェックすることです。

In [1]: import numpy as np 
In [2]: from sortedcontainers import SortedList 
In [3]: a = np.array([1,2,3,4]) 
In [4]: SortedList(a) 
Out[4]: SortedList([1, 2, 3, 4], load=1000) 

しかし、各エントリが配列である2次元のために、そこには明確な真理値がなく、SortedListのは非協力的である:これは、1次元配列のために正常に動作します

In [5]: a.resize(2,2) 
In [6]: a 
Out[6]: 
array([[1, 2], 
     [3, 4]]) 

In [7]: SortedList(a) 
--------------------------------------------------------------------------- 
ValueError        Traceback (most recent call last) 
<ipython-input-7-7a4b2693bb52> in <module>() 
----> 1 SortedList(a) 

/home/me/miniconda3/envs/env/lib/python3.6/site-packages/sortedcontainers/sortedlist.py in __init__(self, iterable, load) 
    81 
    82   if iterable is not None: 
---> 83    self._update(iterable) 
    84 
    85  def __new__(cls, iterable=None, key=None, load=1000): 

/home/me/miniconda3/envs/env/lib/python3.6/site-packages/sortedcontainers/sortedlist.py in update(self, iterable) 
    176   _lists = self._lists 
    177   _maxes = self._maxes 
--> 178   values = sorted(iterable) 
    179 
    180   if _maxes: 

ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all() 

私の現在の回避策があります各行を手動でタプルに変換するには:

sl = SortedList() 
for t in np_array: 
    x, y = t 
    sl.add((x,y)) 

ただし、このソリューションは改善の余地があります。すべての配列をタプルに明示的にアンパックすることなくこの問題を解決する方法を知っている人はいますか?

答えて

1

問題は、配列の真理値がチェックされているということではなく、比較されてソートされるということです。あなたは配列に比較演算子を使用する場合は、配列を取り戻す:

>>> import numpy as np 
>>> np.array([1, 4]) < np.array([2, 3]) 
array([ True, False], dtype=bool) 

得られたこのブール配列は、実際にその真実値sortedによって確認されている配列です。一方

、タプル(またはリスト)と同じ操作は、要素の比較によって要素を行うと、単一のブール値を返します:SortedListはの配列にsortedを使用しようとするので、

>>> (1, 4) < (2, 3) 
True 
>>> (1, 4) < (1, 3) 
False 

numpy配列では、比較演算子から返される単一のブール値が必要なため、比較を行うことはできません。

これを抽象化する1つの方法は、タプルのソート動作を再現するために、__eq__,__lt____gt__などのような比較演算子を実装する新しい配列クラスを作成することです。皮肉なことに、これを行う最も簡単な方法は次のように、タプルへの根本的な配列をキャストするために、次のようになります。この実装では

class SortableArray(object): 

    def __init__(self, seq): 
     self._values = np.array(seq) 

    def __eq__(self, other): 
     return tuple(self._values) == tuple(other._values) 
     # or: 
     # return np.all(self._values == other._values) 

    def __lt__(self, other): 
     return tuple(self._values) < tuple(other._values) 

    def __gt__(self, other): 
     return tuple(self._values) > tuple(other._values) 

    def __le__(self, other): 
     return tuple(self._values) <= tuple(other._values) 

    def __ge__(self, other): 
     return tuple(self._values) >= tuple(other._values) 

    def __str__(self): 
     return str(self._values) 

    def __repr__(self): 
     return repr(self._values) 

、あなたは今SortableArrayオブジェクトのリストを並べ替えることができます。

In [4]: ar1 = SortableArray([1, 3]) 

In [5]: ar2 = SortableArray([1, 4]) 

In [6]: ar3 = SortableArray([1, 3]) 

In [7]: ar4 = SortableArray([4, 5]) 

In [8]: ar5 = SortableArray([0, 3]) 

In [9]: lst1 = [ar1, ar2, ar3, ar4, ar5] 

In [10]: lst1 
Out[10]: [array([1, 3]), array([1, 4]), array([1, 3]), array([4, 5]), array([0, 3])] 

In [11]: sorted(lst1) 
Out[11]: [array([0, 3]), array([1, 3]), array([1, 3]), array([1, 4]), array([4, 5])] 

このかもしれませんあなたが必要とするものについて過度のものになるかもしれませんが、それを行う一つの方法です。どちらの場合でも、比較の際に単一のブール値を返さない一連のオブジェクトに対しては、sortedを使用して逃げることはありません。

forループを避けている場合は、それをリスト内包(つまり、SortedList([tuple(row) for row in np_array]))に置き換えることができます。

+0

ありがとう、これは非常に役に立ちました。また、一般的に、これは本当に良い、よく構造化されたうまく書かれた答えです。良い仕事を続けてください:) – m00am

関連する問題