удалить дубликаты из (кортеж кортежей) - PullRequest
0 голосов
/ 24 октября 2018
input_tuple = (
    (12805,'MLB','NAME1','body NAME1 Noah dev'),         
    (12805,'MLB','NAME2','body NAME2 Noah dev'),
    (12805,'MLB','NAME3','body NAME3 Elijah'),

    (12806,'MLB','NAME4','body NAME4 Liam sev'),
    (12806,'MLB','NAME5','body NAME5 Noah dev'),

    (12807,'MLB','NAME6','body NAME6 Liam sev'),
    (12807,'MLB','NAME7','body NAME7 epic peterson'),

    (12808,'MLB','NAME8','body NAME8 Liam sev'),
    (12808,'MLB','NAME9','body NAME9 epic peterson')         

    )

Обратите внимание на то, что в input_tuple первое место занимают цифры, и нам нужно проверить дубликаты индекса [3], но, пожалуйста, пропустите первые два символа.

ниже приведены два сценария, которые нам нужно посмотреть: -

1) проверка на самодублируемость: теперь, если в 3-м индексе будет обнаружен какой-либо дубликат, нам нужно удалить эту строку

2) для дубликата: после того, как мы проверили самодублирование, мы должны проверить для дубликата, и если что-то найдено, нам нужно заменить первое вхождение

3) для дубликата в паре: в этом сценарии я хочу проверитьчерез дубликат, но проверка должна происходить только в том случае, если есть дубликат пары.я отредактировал в input_tuple в прошлом: например:

    (12808,'MLB','NAME8','body NAME8 Liam sev'),
    (12808,'MLB','NAME9','body NAME9 epic peterson') 

, поскольку его дубликат с ниже:

(12807,'MLB','NAME6','body NAME6 Liam sev'),
(12807,'MLB','NAME7','body NAME7 epic peterson'),

следовательно, это также должно быть устранено.

output_tuple = (
    (12805,'MLB','NAME1','body NAME1 Noah dev'),
    (12805,'MLB','NAME3','body NAME3 Elijah dev'),

    (12806,'MLB','NAME4','body NAME4 Liam sev'),
    (12806,'MLB','NAME1','body NAME1 Noah dev'),

    (12807,'MLB','NAME4','body NAME4 Liam sev'),
    (12807,'MLB','NAME7','body NAME7 epic peterson')
    )

Код, который я попробовал: (работает нормально в 1-м сценарии)

def skip_two_words(str):
    str = ' '.join(str.split(' ')[2:])
    return str

input_tuple = (tuple({(x[0], skip_two_words(x[3])): x for x in 
input_tuple[::-1]}.values())[::-1])

    id_name_dict = defaultdict(list)
    for id, _, _, name in input_tuple:
        id_name_dict[id].append(name)
    seen = set()
    ignore_id_set = set()
    for _id, _namelst in id_name_dict.items():
            id = tuple(sorted(_namelst))
            if id not in seen:
                seen.add(id)
            else:
                ignore_id_set.add(_id)  # duplicate
    del id_name_dict, seen  # id_name_dict,seen are now eligible for garbage 
    collection
    output_tuple = tuple(item for item in input_tuple if item[0] not in 
    ignore_id_set)

1 Ответ

0 голосов
/ 25 октября 2018

Не нужно заново изобретать колесо, чтобы отбрасывать дубликаты.У itertools документов есть unique_everseen рецепт , также доступный в сторонних библиотеках через more_itertools.unique_everseen или toolz.unique.Вторая часть немного грязная, но вы можете использовать пользовательскую функцию для определения ваших разбиений, а затем использовать понимание кортежей.

from toolz import unique

# drop duplicates
res = tuple(unique(input_tuple, key=lambda x: (x[0], tuple(x[-1].split()[2:]))))

# make mapping dictionary
d = {' '.join(tup[-1].split()[2:]): tup[-2] for tup in reversed(input_tuple)}

# apply dictionary mapping with some splits
def return_tup(tup, d):
    num, cat, name_id, full = tup
    full_split = full.split()
    name_words = ' '.join(full_split[2:])
    name_id = d[name_words]
    full = ' '.join([full_split[0], name_id, name_words])
    return num, cat, name_id, full

res = tuple(return_tup(tup, d) for tup in res)

((12805, 'MLB', 'NAME1', 'body NAME1 Noah dev'),
 (12805, 'MLB', 'NAME3', 'body NAME3 Elijah'),
 (12806, 'MLB', 'NAME4', 'body NAME4 Liam sev'),
 (12806, 'MLB', 'NAME1', 'body NAME1 Noah dev'),
 (12807, 'MLB', 'NAME4', 'body NAME4 Liam sev'),
 (12807, 'MLB', 'NAME7', 'body NAME7 epic peterson'))
...