我试图根据一些非平凡的比较逻辑对对象列表进行排序,但是发现比较困难,因为在Python中,自定义排序功能仅接受1个参数。例如,在Java中,sort函数将引用object1
和object2
,从而可以轻松地进行比较。
class Point:
def __init__(self, char, num, pt_type):
self.char = char
self.num = num
self.pt_type = pt_type # 'start' or 'end'
def __str__(self):
return str([self.char, str(self.num), self.pt_type])
def __repr__(self):
return str(self)
arr = [Point('C', 1, 'end'), Point('C', 9, 'start'),
Point('B', 7, 'end'), Point('B', 2, 'end'),
Point('A', 3, 'start'), Point('A', 6, 'start')]
def my_sort(key):
# Sort by first element (letter).
#
# If the letter is the same, fallback to sorting by the
# 2nd element (number), but the logic of this comparison depends
# on `pt_type`:
# -If Point1 and Point2 both have type 'start', pick the higher number first.
# -If Point1 and Point2 both have type 'end', pick the lower number first.
# -If Point1 and Point2 have different types, pick the 'start' type first.
return key.char
print(sorted(arr, key=my_sort))
预期的排序顺序应为:
[Point('A', 6, 'start'), Point('A', 3, 'start')
Point('B', 2, 'end'), Point('B', 7, 'end'),
Point('C', 9, 'start'), Point('C', 1, 'end')]
我什至不知道如何开始执行所需的逻辑,所以我很感激朝着正确的方向前进。
答案 0 :(得分:3)
我将使用以下key
函数:
class Point:
def __init__(self, char, num, pt_type):
self.char = char
self.num = num
self.pt_type = pt_type # 'start' or 'end'
def __str__(self):
return str([self.char, str(self.num), self.pt_type])
def __repr__(self):
return str(self)
arr = [Point('C', 1, 'end'), Point('C', 9, 'start'),
Point('B', 7, 'end'), Point('B', 2, 'end'),
Point('A', 3, 'start'), Point('A', 6, 'start')]
def key(p):
return p.char, int(p.pt_type != 'start'), p.num if p.pt_type == 'end' else -1 * p.num
result = sorted(arr, key=key)
print(result)
输出
[['A', '6', 'start'], ['A', '3', 'start'], ['B', '2', 'end'], ['B', '7', 'end'], ['C', '9', 'start'], ['C', '1', 'end']]
key函数创建一个元组用作键,如果节点的类型为'start',则第一个元素为字母,第二个元素为0;如果'end'类型,则为1。如果最后一个元素的类型为“开始”,则为负;如果最后一个元素的类型为“结束”,则为正。
答案 1 :(得分:2)
您可以对类的属性进行排序,然后使用sorted
。这种方法的好处:无需付出额外的努力,您就可以通过比较运算符(例如>
,<
,==
)来比较对象。
__eq__
和__lt__
方法至少应指定__eq__
和__lt__
方法:
class Point:
def __init__(self, char, num, pt_type):
self.char = char
self.num = num
self.pt_type = pt_type # 'start' or 'end'
def __str__(self):
return str([self.char, str(self.num), self.pt_type])
def __repr__(self):
return str(self)
def __eq__(self, other):
return self.char == other.char and self.pt_type == other.pt_type
def __lt__(self, other):
if self.char != other.char:
return self.char < other.char
if (self.pt_type == 'start') and (other.pt_type == 'start'):
return self.num > other.num
elif (self.pt_type == 'end') and (other.pt_type == 'end'):
return self.num < other.num
else:
return self.pt_type == 'start'
可以通过functools.total_ordering
简化添加其他比较方法,例如__gt__
,__ge__
等:
from functools import total_ordering
@total_ordering
class Point:
def __init__(self, ...):
# initialization logic
def __eq__(self, other):
# as before
def __lt__(self, other):
# as before
arr = [Point('C', 1, 'end'), Point('C', 9, 'start'),
Point('B', 7, 'end'), Point('B', 2, 'end'),
Point('A', 3, 'start'), Point('A', 6, 'start')]
print(sorted(arr))
[['A', '6', 'start'],
['A', '3', 'start'],
['B', '2', 'end'],
['B', '7', 'end'],
['C', '9', 'start'],
['C', '1', 'end']]
答案 2 :(得分:1)
您想对cmp
使用sorted
参数,该参数具有2个参数的比较功能:
https://docs.python.org/2/library/functions.html#sorted
供您参考,key
函数将从要排序的每个项目计算一个派生值,并根据该值进行排序,例如按照对中的第二个值对对列表进行排序:sorted(items, key=lambda x: x[1])