'<' иногда не поддерживается при сортировке списка кортежей с помощью zip () - PullRequest
2 голосов
/ 07 мая 2020

Я хочу отсортировать список на основе второго списка, как в это сообщение о переполнении стека. В моем случае мой код пытается отсортировать объекты Chromo по их соответствующим fitness_weights, поэтому я попробовал решения в связанном сообщении:

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 раза

Как исправить?

1 Ответ

7 голосов
/ 07 мая 2020

Ошибка возникает, когда у вас есть две пары (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'

Вы можете избежать этой проблемы либо с помощью настраиваемого ключа сортировки, который извлекает только вес, или путем добавления в ie прерывателя, уникального для каждого значения в отсортированной последовательности, например счетчика:

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 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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...