使用 zip() 对元组列表进行排序时有时不支持'<'



我想根据第二个列表对列表进行排序,就像这篇堆栈溢出文章中一样。在我的例子中,我的代码试图根据相应的fitness_weightsChromo对象进行排序,所以我在链接的帖子上尝试了解决方案:

def foobar():
...
chromolist = [x for _, x in sorted(zip(fitness_weights, chromolist))]
...

给出错误:

TypeError: '<' not supported between instances of 'Chromo' and 'Chromo'

调试我尝试:

def foobar():
...
try:
chromolist = [x for _, x in sorted(zip(fitness_weights, chromolist))]
except Exception as e:
print(fitness_weights)
print(chromolist)
print([i for i in zip(fitness_weights, chromolist)])
raise e
print('works fine')
...

输出:

works fine
works fine
works fine
works fine
works fine
works fine
works fine
works fine
works fine
works fine
works fine
works fine
works fine
works fine
works fine
works fine
works fine
works fine
works fine
works fine
works fine
works fine
[2630793242, 2662598634, 1204127226, 1218205610, 1224753838, 1212750850, 
1212293610, 1221507266, 1269226518, 1363578674, 1209661338, 2674408754, 
1179213986, 1209887778, 2281636710, 1906925334, 1156258126, 1287144442, 
1218205610, 1256241498, 2926198286, 1533442630, 1587421406, 2685579290, 
1203563674, 1205066274, 1181576990, 1188462746, 1127834446, 2295554650, 
1216261042, 1193222146, 1191591394, 1206052810, 1206800842, 1213410890, 
1202786310, 1230097202, 1277296358, 1218982810]
[Chromo Object, Chromo Object, Chromo Object, Chromo Object, Chromo Object, 
Chromo Object, Chromo Object, Chromo Object, Chromo Object, Chromo Object, 
Chromo Object, Chromo Object, Chromo Object, Chromo Object, Chromo Object, 
Chromo Object, Chromo Object, Chromo Object, Chromo Object, Chromo Object, 
Chromo Object, Chromo Object, Chromo Object, Chromo Object, Chromo Object, 
Chromo Object, Chromo Object, Chromo Object, Chromo Object, Chromo Object, 
Chromo Object, Chromo Object, Chromo Object, Chromo Object, Chromo Object, 
Chromo Object, Chromo Object, Chromo Object, Chromo Object, Chromo Object]
[(2630793242, Chromo Object), (2662598634, Chromo Object), 
(1204127226, Chromo Object), (1218205610, Chromo Object),
(1224753838, Chromo Object), (1212750850, Chromo Object),
(1212293610, Chrom Object), (1221507266, Chromo Object), 
(1269226518, Chromo Object), (1363578674, Chromo Object), 
(1209661338, Chromo  Object), (2674408754, Chromo Object),
(1179213986, Chromo Object), (1209887778, Chromo Object), 
(2281636710, Chromo Object), (1906925334, Chromo Object), 
(1156258126, Chromo Object), (1287144442, Chromo Object), 
(1218205610, Chromo  Object), (1256241498, Chromo Object),
(2926198286, Chromo Object), (1533442630, Chromo Object), 
(1587421406, Chromo Object), (2685579290, Chromo Object), 
(1203563674, Chromo Object), (1205066274, Chromo Object), 
(1181576990, Chromo  Object), (1188462746, Chromo Object), 
(1127834446, Chromo Object), (2295554650, Chromo Object),
(1216261042, Chromo Object), (1193222146, Chromo Object), 
(1191591394, Chromo Object), (1206052810, Chromo Object), 
(1206800842, Chromo  Object), (1213410890, Chromo Object), 
(1202786310, Chromo Object), (1230097202, Chromo Object), 
(1277296358, Chromo Object), (1218982810, Chromo Object)]

这令人困惑,因为:

  • 所有数据类型都是正确的
  • 该功能正确工作了22次

如何解决此问题?

当您有两个权重相等的(weight, chromo)对时,会发生错误,此时Python试图比较chromo值:

>>> class Chromo:
...     pass
...
>>> chromolist = [Chromo(), Chromo()]
>>> fitness_weights = [42, 42]
>>> sorted(zip(fitness_weights, chromolist))
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: '<' not supported between instances of 'Chromo' and 'Chromo'

您可以通过使用只提取权重的自定义排序键,或者添加一个对排序序列中的每个值都唯一的平局决胜符(如计数器(来避免这个问题:

from itertools import count
chromolist = [x for *_, x in sorted(zip(fitness_weights, count(), chromolist))]

计数器只是为了确保Python永远不会查看Chromo实例,因为现在每个元素都是(weight, unique_integer, Chromo)元组:

>>> from itertools import count
>>> sorted(zip(fitness_weights, count(), chromolist))
[(42, 0, <__main__.Chromo object at 0x1038cfa00>), (42, 1, <__main__.Chromo object at 0x103a396d0>)]

排序键只是一个生成要比较的值的函数,您可以使用lambda(lambda t: t[0](或operator.itemgetter()对象:

from operator import itemgetter
chromolist = [x for _, x in sorted(zip(fitness_weights, chromolist), key=itemgetter(0))]

按键功能需要在输入列表上进行单独的传递,因此速度稍微慢一点,正如在这个有200个输入的简单时间试验中所看到的那样:

>>> from timeit import timeit
>>> fw = fitness_weights * 100
>>> cl = chromolist * 100
>>> timeit('sorted(zip(fw, count(), cl))', globals=globals(), number=100000)
1.4618491119981627
>>> timeit('sorted(zip(fw, cl), key=itemgetter(0))', globals=globals(), number=100000)
1.6409574589997646

相关内容

最新更新