удалить избыточность в списке с кортежем из трех элементов - PullRequest
0 голосов
/ 04 декабря 2018

У меня есть список кортежей, похожих на 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?Любая помощь будет оценена!

Ответы [ 5 ]

0 голосов
/ 04 декабря 2018

Вы можете сделать это, используя хэш-карту следующим образом:

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()]
0 голосов
/ 04 декабря 2018

Это решение сохраняет исходный порядок кортежей, предполагая, что каждый кортеж (в целом) уникален;в случае наличия дубликатов кортежей будет возвращено последнее появление каждого кортежа:

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)]]
0 голосов
/ 04 декабря 2018

Если вы можете позволить себе игнорировать порядок, вы можете использовать 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)]
0 голосов
/ 04 декабря 2018

Если я правильно понимаю, вот решение 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)]]
0 голосов
/ 04 декабря 2018

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

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

Используя это, ваш дикт будет преобразовывать 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

Таким образом, порядок также будет сохранен.

...