У меня есть список кортежей, похожих на A:
A = [[(90, 1, 5), (126, 1, 3), (139, 1, 3), (1000, 1, 5), (111, 1, 2), (176, 1, 5)],
[(160, 2, 5), (1000, 2, 5), (111, 1, 2)],
[(134, 3, 5), (126, 1, 3), (128, 3, 4), (139, 1, 3)],
[(128, 3, 4)],
[(90, 1, 5), (160, 2, 5), (134, 3, 5), (1000, 2, 5), (1000, 1, 5), (176, 1, 5)]]
В каждой строке этого списка могут быть кортежи, второй и третий элементы которых совпадают. Например, в A [0]:
A[0] = [(90, 1, 5), (126, 1, 3), (139, 1, 3), (1000, 1, 5), (111, 1, 2), (176, 1, 5)]
(90, 1, 5), (1000, 1, 5) и (176, 1, 5) имеют одинаковые второй и третий элементы. Среди них мне нужно сохранить тот, который имеет максимальное значение для первого элемента, и удалить два других. Итак, я должен иметь возможность сохранить (1000, 1, 5) и удалить (90, 1, 5) и (176, 1, 5) из A [0].
Было бы лучше сохранить порядок в списке.
Есть ли способ сделать это итеративно для всех строк в A? Любая помощь будет оценена по достоинству!
@slider Было бы лучше сохранить порядок в списке, но если нет возможности, то я должен игнорировать сохранение порядка в списке.
если ваши исходные данные могут быть изменены, я предлагаю использовать словарь с ключом кортежа, использующим второй и третий элементы, и значением, являющимся вашим первым элементом. Таким образом, вы можете легко обновить максимальные значения, особенно если у вас большой набор данных.
Здесь полезный ответ: удаление дубликатов с сохранением порядка.
@ Я новичок в Python, могу ли я поподробнее рассказать? или напишите ту часть кода, которая, по вашему мнению, подойдет?
@timgeb Я думаю, вы говорите об A [2]. Это должно стать: [(134, 3, 5), (128, 3, 4), (139, 1, 3)]. Следовательно, (126, 1, 3) следует удалить из A [2].






Использование словарей:
fin = []
for row in A:
dict = {}
for tup in row:
dict[tup[1:2]] = tup[0]
fin.append(dict)
A = [[value, t1, t1] for (t1, t2), value in dict.iteritems()]
Используя это, ваш dict преобразует A [0] из
A[0] = [(90, 1, 5), (126, 1, 3), (139, 1, 3), (1000, 1, 5), (111, 1, 2), (176, 1, 5)]
к
{ (1,5): 1000, (1,3): 139, (1,2): 111 } (as a dict)
и затем может быть преобразован обратно в массив с помощью iteritems
Таким образом, порядок также будет сохранен.
Если вы можете позволить себе игнорировать порядок, вы можете использовать itertools.groupby для группировки элементов по 2-му и 3-му элементам в списке, отсортированном в порядке возрастания 2-го и 3-го элементов и порядке убывания первого элемента. Тогда первый элемент каждой группы - ваш желаемый выбор:
from itertools import groupby
A = [[(90, 1, 5), (126, 1, 3), (139, 1, 3), (1000, 1, 5), (111, 1, 2), (176, 1, 5)],
[(160, 2, 5), (1000, 2, 5), (111, 1, 2)],
[(134, 3, 5), (126, 1, 3), (128, 3, 4), (139, 1, 3)],
[(128, 3, 4)],
[(90, 1, 5), (160, 2, 5), (134, 3, 5), (1000, 2, 5), (1000, 1, 5), (176, 1, 5)]]
def max_duplicate(lst):
res = []
for k, g in groupby(sorted(lst, key=lambda x: (x[1], x[2], -x[0])), key=lambda x: (x[1], x[2])):
res.append(next(g))
return res
result = [max_duplicate(l) for l in A]
for r in result:
print(r)
Вывод
[(111, 1, 2), (139, 1, 3), (1000, 1, 5)]
[(111, 1, 2), (1000, 2, 5)]
[(139, 1, 3), (128, 3, 4), (134, 3, 5)]
[(128, 3, 4)]
[(1000, 1, 5), (1000, 2, 5), (134, 3, 5)]
Если я правильно понял, вот решение для itertools.groupby. Я предполагаю, что порядок в конечном результате не имеет значения.
from itertools import groupby
def keep_max(lst, groupkey, maxkey):
'groups lst w.r.t. to groupkey, keeps maximum of each group w.r.t. maxkey'
sor = sorted(lst, key=groupkey)
groups = (tuple(g) for _, g in groupby(sor, key=groupkey))
return [max(g, key=maxkey) for g in groups]
В действии:
>>> from operator import itemgetter
>>> groupkey = itemgetter(1, 2)
>>> maxkey = itemgetter(0)
>>> A = [[(90, 1, 5), (126, 1, 3), (139, 1, 3), (1000, 1, 5), (111, 1, 2), (176, 1, 5)], [(160, 2, 5), (1000, 2, 5), (111, 1, 2)], [(134, 3, 5), (126, 1, 3), (128, 3, 4), (139, 1, 3)], [(128, 3, 4)], [(90, 1, 5), (160, 2, 5), (134, 3, 5), (1000, 2, 5), (1000, 1, 5), (176, 1, 5)]]
>>>
>>> [keep_max(sub, groupkey, maxkey) for sub in A]
[[(111, 1, 2), (139, 1, 3), (1000, 1, 5)],
[(111, 1, 2), (1000, 2, 5)],
[(139, 1, 3), (128, 3, 4), (134, 3, 5)],
[(128, 3, 4)],
[(1000, 1, 5), (1000, 2, 5), (134, 3, 5)]]
Это решение сохраняет исходный порядок кортежей, предполагая, что каждый кортеж (в целом) уникален; если есть повторяющиеся кортежи, это вернет последнее появление каждого кортежа:
from operator import itemgetter
A = [[(90, 1, 5), (126, 1, 3), (139, 1, 3), (1000, 1, 5), (111, 1, 2), (176, 1, 5)],
[(160, 2, 5), (1000, 2, 5), (111, 1, 2)],
[(134, 3, 5), (126, 1, 3), (128, 3, 4), (139, 1, 3)],
[(128, 3, 4)],
[(90, 1, 5), (160, 2, 5), (134, 3, 5), (1000, 2, 5), (1000, 1, 5), (176, 1, 5)]]
def uniques(lst):
groups = {}
for t in lst:
groups.setdefault(t[1:], []).append(t)
lookup = {t: i for i, t in enumerate(lst)}
index = lookup.get
first = itemgetter(0)
return sorted(map(lambda x: max(x, key=first), groups.values()), key=index)
result = [uniques(a) for a in A]
print(result)
Вывод
[[(139, 1, 3), (1000, 1, 5), (111, 1, 2)], [(1000, 2, 5), (111, 1, 2)], [(134, 3, 5), (128, 3, 4), (139, 1, 3)], [(128, 3, 4)], [(134, 3, 5), (1000, 2, 5), (1000, 1, 5)]]
Вы можете сделать это, используя хэш-карту следующим образом:
d = {}
for a in A:
for aa in a:
v, k1, k2 = aa
if (k1, k2) in d:
d[(k1, k2)] = max(v, d[(k1, k2)])
else:
d[(k1, k2)] = v
l = [[v, k1, k2] for (k1, k2), v in d.iteritems()]
Важно ли сохранять исходный порядок в списках?