按成员变量正确排序列表

2024-06-16 14:36:18 发布

您现在位置:Python中文网/ 问答频道 /正文

我正在尝试按成员变量对对象列表进行排序。通过检查堆栈溢出,我发现了以下方法。但是,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

请帮忙。谢谢。你知道吗


Tags: 方法keyselfnonesearchfoodefitem
3条回答

你在整理字符串。例如,字符串'12'位于'2'之前。如果要按数字排序,请将它们转换为数字。你知道吗

您要确保将键作为int而不是字符串进行比较,当您使用字符串时,它们是按字母顺序排序的,即'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属性将是数字的,那么您可以稍微简化代码。你知道吗

啊,是的。老话说,“把它放在一个自然的顺序!”问题。你知道吗

翻译一个我从Tye McQueen那里得到的Perl老技巧,类似这样的东西应该适用于字符串:

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%的情况下人们所期望的嵌入数字。你知道吗

相关问题 更多 >