Удалить избыточность в списке с кортежем из трех элементов

У меня есть список кортежей, похожих на 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 04.12.2018 20:16

@slider Было бы лучше сохранить порядок в списке, но если нет возможности, то я должен игнорировать сохранение порядка в списке.

user9439906 04.12.2018 20:19

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

Abhishek Patel 04.12.2018 20:19

Здесь полезный ответ: удаление дубликатов с сохранением порядка.

blacksite 04.12.2018 20:20

@ Я новичок в Python, могу ли я поподробнее рассказать? или напишите ту часть кода, которая, по вашему мнению, подойдет?

user9439906 04.12.2018 20:21

@timgeb Я думаю, вы говорите об A [2]. Это должно стать: [(134, 3, 5), (128, 3, 4), (139, 1, 3)]. Следовательно, (126, 1, 3) следует удалить из A [2].

user9439906 04.12.2018 20:26
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
1
6
106
5
Перейти к ответу Данный вопрос помечен как решенный

Ответы 5

Использование словарей:

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()]

Другие вопросы по теме