按成员变量正确排序列表

时间:2015-11-05 00:26:10

标签: python algorithm sorting data-structures

我试图按成员变量对对象列表进行排序。通过堆栈溢出,我发现了以下方法。但是, lsort 逐位比较,因此5,3,7,21,64将排序为21,3,5,64,7(我希望这是数字:3,5 ,7,21,64)。我不确定如何解决这个问题,因为有些键可能看起来像D239,D97,D11( lsort 就像D11,D239,D97;我希望它看起来像D11,D97 ,D239)。虽然我更喜欢一种方法,但我猜两种方法都可以。

import operator 

class foo:
    def __init__(self, key1, data1, data2):
        #all of these values are strings, even though some may be ints
        self.key = key1
        self.d1 = data1
        self.d2 = data2

#sorts list l by member variable search
def lsort (l, search):
    #this doesn't actually work very well.
    #key can be int or string
    #when key is an int, this seems to order by number of digits, then low to high
    #(e.g. 11, 12, 40, 99, 3, 6, 8)
    return sorted(l, key=operator.attrgetter(search))


l1 = [foo('12', 'foo1', None), foo('8', 'qwer', None), foo('7', 'foo3', None), foo('13', 'foo2', None), foo('77', 'foo4', None), foo('12', 'foo5', None) ]


for item in lsort(l1, 'key'):
    print item.key, item.d1, item.d2

输出:

12 foo1 None 
12 foo5 None 
13 foo2 None
7 foo3 None
77 foo4 None
8 qwer None

预期:

7 foo3 None
8 qwer None
12 foo1 None
12 foo5 None
13 foo2 None
77 foo4 None

为什么会这样?我使用相同的排序并在一个非常基础的类上运行它似乎工作正常。

class foo:
    def __init__(self, d1):
        self.bar= d1

请协助。感谢。

4 个答案:

答案 0 :(得分:1)

啊,是的。旧的,"只是把它放在一个自然的顺序!"问题

从Tye McQueen翻译我在Perl中获得的旧hack,这样的东西应该适用于字符串:

import re

def replace_match(match):
    value = match.group(0)
    if value[0] == ".":
        return value
    else:
        return ("0"*(9-len(value))) + value

def replace_with_natural(string):
    return re.sub("(\.\d*|[1-9]\d{0,8})", replace_match, string)

items = ["hello1", "hello12", "foo12.1", "foo12.05", "hello3", "foo.12.12"]
print(sorted(items, key=replace_with_natural))

我们的想法是,我们用一些固定长度替换字符串中的每个数字,按照我们喜欢的方式按字典顺序排序。

请注意,像这样的任何函数都会遇到处理不当的问题。在这种情况下,科学记数处理不当。但是,这将达到人们对99.99%的嵌入数字所期望的效果。

答案 1 :(得分:1)

当您使用按字母顺序排序的字符串,即'7' > '11'时,您需要确保将密钥作为整数而不是字符串进行比较。最简单的方法是为foo类定义自己的自定义比较方法:

from functools import total_ordering

@total_ordering
class foo:
    def __init__(self, key1, data1, data2):
        #all of these values are strings, even though some may be ints
        self.key = key1
        self.d1 = data1
        self.d2 = data2

    @staticmethod
    def _as_int(value):
        try:
            return int(value)
        except ValueError:
            return value

    def __le__(self, other):
        return self._as_int(self.key) < self._as_int(other.key)
    def __eq__(self, other):
        return self._as_int(self.key) == self._as_int(other.key)

l1 = [foo('12', 'foo1', None),
      foo('8', 'qwer', None),
      foo('7', 'foo3', None),
      foo('13', 'foo2', None),
      foo('77', 'foo4', None),
      foo('12', 'foo5', None),
      foo('A', 'foo', None),
      foo('B', 'foo', None)]

for item in sorted(l1):
    print item.key, item.d1, item.d2

给出了:

7 foo3 None
8 qwer None
12 foo1 None
12 foo5 None
13 foo2 None
77 foo4 None
A foo None
B foo None

如果您确定key属性是数字,则可以稍微简化代码。

答案 2 :(得分:0)

您正在排序字符串。例如,字符串'12'位于'2'之前。如果要按数字排序,请将它们作为数字投射。

答案 3 :(得分:0)