web-dev-qa-db-ja.com

なしにすることができる属性によるリストのソート

を使用してオブジェクトのリストを並べ替えようとしています

my_list.sort(key=operator.attrgetter(attr_name))

ただし、リストアイテムのいずれかに_attr = None_ではなく_attr = 'whatever'_がある場合、

次に、TypeError: unorderable types: NoneType() < str()を取得します

Py2では問題ありませんでした。 Py3でこれを処理するにはどうすればよいですか?

23
AlexVhr

順序比較演算子は、Python 3で説明されているように、タイプについてより厳密です ここ

順序比較演算子(<、<=、> =、>)は、オペランドに意味のある自然順序がない場合にTypeError例外を発生させます。

Python 2は、任意の文字列(空の文字列でも)の前にNoneを並べ替えます。

>>> None < None
False

>>> None < "abc"
True

>>> None < ""
True

Python 3で、NoneTypeインスタンスを注文しようとすると、例外が発生します。

>>> None < "abc"
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unorderable types: NoneType() < str()

私が考えることができる最も簡単な修正は、Noneインスタンスを""のような順序付け可能なものに明示的にマップすることです。

my_list_sortable = [(x or "") for x in my_list]

データをそのままにしてソートしたい場合は、sortにカスタマイズされたkeyメソッドを指定してください。

def nonesorter(a):
    if not a:
        return ""
    return a

my_list.sort(key=nonesorter)
24
jsalonen

一般的な解決策として、他のどのオブジェクトよりも比較が少ないオブジェクトを定義できます。

from functools import total_ordering

@total_ordering
class MinType(object):
    def __le__(self, other):
        return True

    def __eq__(self, other):
        return (self is other)

Min = MinType()

次に、リスト内のMin値をNoneに置き換えるソートキーを使用します

mylist.sort(key=lambda x: Min if x is None else x)
26
augurar

ここで提案されたソリューションは機能しますが、これはさらに短縮できます。

mylist.sort(key=lambda x: x or 0)

基本的に、Noneは値0であるかのように扱うことができます。

例えば。:

>>> mylist = [3, 1, None, None, 2, 0]
>>> mylist.sort(key=lambda x: x or 0)
>>> mylist
[None, None, 0, 1, 2, 3]
7
fralau

None以外にも文字列に匹敵しないものがあるので(初心者向けのintとlists)、一般的な問題に対するより堅牢な解決策を次に示します。

_my_list.sort(key=lambda x: x if isinstance(x, str) else "")
_

これにより、文字列とstrから派生したすべてのタイプを比較し、他のすべてを空の文字列でビンに入れることができます。または、必要に応じて、別のデフォルトのデフォルトキーに置き換えます。 _"ZZZZ"_またはchr(sys.maxunicode)を使用して、このような要素を最後にソートします。

3
alexis