На этом шаге мы рассмотрим способ решения этой задачи.
Вы хотите исключить дублирующиеся значения из последовательности, но при этом сохранить порядок следования оставшихся элементов.
Если значения в последовательности являются хешируемыми, задача может быть легко решена с использованием множества и генератора. Например:
>>> def dedupe(items): seen = set() for item in items: if item not in seen: yield item seen.add(item)
Вот пример использования этой функции:
>>> a = [1, 5, 2, 1, 9, 1, 5, 10] >>> list(dedupe(a)) [1, 5, 2, 9, 10] >>>
Это будет работать только в том случае, если элементы последовательности хешируются. Если вы пытаетесь удалить дубликаты в последовательности из нехешируемых типов (таких как словари), то можете внести небольшое изменение в этот рецепт. Например, такое:
>>> def dedupe(items, key=None): seen = set() for item in items: val = item if key is None else key(item) if val not in seen: yield item seen.add(val)
Аргумент key здесь нужен для определения функции, которая конвертирует элементы последовательности в хешируемый тип, подходящий для поиска дубликатов. Вот как это работает:
>>> a = [{'x': 1, 'y': 2}, {'x': 1, 'y': 3}, {'x': 1, 'y': 2}, {'x': 2, 'y': 4}]
>>> list(dedupe(a, key=lambda d: (d['x'],d['y'])))
[{'x': 1, 'y': 2}, {'x': 1, 'y': 3}, {'x': 2, 'y': 4}]
>>> list(dedupe(a, key=lambda d: d['x']))
[{'x': 1, 'y': 2}, {'x': 2, 'y': 4}]
>>>
Последнее решение также отлично работает, если вам нужно удалить дубликаты, базируясь на значении одного поля или атрибута либо более крупной
структуры данных.
Если вы просто хотите удалить дубликаты, то часто достаточно будет создать множество. Например:
>>> a [1, 5, 2, 1, 9, 1, 5, 10] >>> set(a) {1, 2, 10, 5, 9} >>>
Однако этот поход не сохраняет какой бы то ни было порядок, поэтому результат будет перемешан. Показанные выше решения помогают избежать этого.
Использование функции-генератора в этом рецепте отражает тот факт, что вы наверняка хотите написать функцию максимально широкого назначения, а не напрямую привязанную к обработке списков. Например, если вы хотите читать файл, удаляя дублирующиеся строки, то можете сделать так:
with open(somefile,'r') as f: for line in dedupe(f): . . . .
Передача функции в аргументе key имитирует похожую возможность во встроенных функциях, таких как sorted(), min() и max().
На следующем шаге мы рассмотрим присваивание имен срезам.