我试图按成员变量对对象列表进行排序。通过堆栈溢出,我发现了以下方法。但是, 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
请协助。感谢。
答案 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)