python3通过多个命名属性对对象进行排序

时间:2016-06-24 20:04:26

标签: sorting python-3.x

我在Python 3.5.1中有一个对象列表,其中包含几个命名属性。该列表表示一组C变量,因此每个对象有三个命名属性,对应于三种常见的基本类型:uint8,uint16和uint32。

class variableList(object):
    def __init__(self, eight, sixteen, thirtytwo):
        self.size_8 = eight
        self.size_16 = sixteen
        self.size_32 = thirtytwo

这些命名属性的值为(Nonetype) None(str)'E'。对于每个对象,只有一个命名属性具有一些非None值。

我想对这个对象列表进行排序,使得size_32的非None值的所有对象都位于顶部,然后是size_16,后跟size_8。

在python 2.7.1中我成功地使用了它,但感觉就像是黑魔法:

size_filtered_list = sorted(filtered_list, key=lambda y: (y.size_32, y.size_16, y.size_8))

但在3.5.1中这不再适用。建议?

2 个答案:

答案 0 :(得分:1)

您应该转向使用兼容类型;排序None'E'是荒谬的,而Python 2"任意但一致的"不兼容类型的排序规则允许它,这是一种可怕的做法。如果唯一的值是None'E',那么它们实际上只是可怕的布尔值版本;您可以轻松使用FalseTrue,并且您的key函数在Py2和Py3中都能正常工作;你甚至可以优化"与operator.attrgetter

一点点
from operator import attrgetter

size_filtered_list = sorted(filtered_list, key=attrgetter('size_32', 'size_16', 'size_8'))

或者,使用原始基于lambda的代码,您可以通过将None替换为key中的空字符串来使其工作,因此您可以比较兼容类型(同时仍然处理None少于其他所有字符串):

size_filtered_list = sorted(filtered_list, key=lambda y: (y.size_32 or '', y.size_16 or '', y.size_8 or ''))

这有点愚蠢,但是None'E'使用布尔数据也是如此。

答案 1 :(得分:0)

我只是为类实现比较运算符。假设您不希望根据存储在每个属性中的值进行排序,则此实现应该有效。

class variableList(object):
    def __init__(self, eight, sixteen, thirtytwo):
        self.size_8 = eight
        self.size_16 = sixteen
        self.size_32 = thirtytwo

    def __lt__(self, other):
        if self.size_8 is not None:
            return self != other
        elif self.size_16 is not None:
            return True if other.size_32 is not None else False
        else:
            return False

    def __eq__(self, other):
        if self.size_8 is not None:
            return other.size_8 is not None
        elif self.size_16 is not None:
            return other.size_16 is not None
        else:
            return other.size_32 is not None

为了完整起见,您还可以实现大于运算符,但不需要进行排序:

    def __gt__(self, other):
        if self.size_32 is not None:
            return self != other
        elif self.size_16 is not None:
            return False if other.size_32 is not None else True
        else:
            return False

如果要对相同类型的值进行排序,则必须添加另一级别的嵌套来比较这些值。