У меня периодически всплывает вопрос: как в Питоне удалить в списке дублирующиеся элементы (из [1, 2, 2, 3] получить [1, 2, 3]). Я знаю один способ-хак:

lst = dict([(item, None) for item in lst]).keys()

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

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

Так вот, не знает ли кто какой-нибудь способ поэлегантней?

Комментарии: 11

  1. bogus

    тут: http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/52560

    способ все тот же в целом... ну и коменты рулят...

  2. Konstantin

    Почему бы не воспользоваться set:

    lst = set(lst)

    или:

    lst = list(set(lst))

    Работает только в python >=2.4, если я не ошибаюсь.

  3. Иван Сагалаев

    О, множества — это интересно! Спасибо.

    Хотя тоже вариант не на все случаи, потому что порядок не схраняют. Как, впрочем, и способ через dict.

  4. Grigoriy Petukhov

    Python Cookbook от О'Рейли - неплохая книженция.
    В частности, там есть рецепты по удалению дубликатов из списков. Далее код.
    Порядок не сохраняется:

    # support 2.3 as well as 2.4
    
    try: set
    except NameError: from sets import Set as set
    def unique(s):
        """ Return a list of the elements in s in arbitrary order, but without
            duplicates. """
        # Try using a set first, because it's the fastest and will usually work
        try:
            return list(set(s))
         except TypeError:
            pass  # Move on to the next method
        # Since you can't hash all elements, try sorting, to bring equal items
        # together and then weed them out in a single pass
        t = list(s)
        try:
            t.sort( )
        except TypeError:
            del t  # Move on to the next method
        else:
            # the sort worked, so we're fine -- do the weeding
            return [x for i, x in enumerate(t) if not i or x != t[i-1]]
        # Brute force is all that's left
        u = [  ]
        for x in s:
            if x not in u:
                u.append(x)
        return u
    

    Порядок сохраняется:

    # support 2.3 as well as 2.4
    
    try: set
    except NameError: from sets import Set as set
    
    # f defines an equivalence relation among items of sequence seq, and
    # f(x) must be hashable for each item x of seq
    
    def uniquer(seq, f=None):
        """ Keeps earliest occurring item of each f-defined equivalence class """
        if f is None:    # f's default is the identity function f(x) -> x
            def f(x): return x
        already_seen = set( )
        result = [  ]
        for item in seq:
            marker = f(item)
            if marker not in already_seen:
                 already_seen.add(marker)
                 result.append(item)
        return result
    
  5. Mkdir
    >>> d = [1, 1, 2, 2, 3, 3]
    >>> list(set(d))
    [1, 2, 3]
    
  6. wiz

    Если порядок не важен, то set. Если важен, то словарь + your_list.index()

  7. Александр Пискарёв

    А попробуйте вот это :)

    lst2=reduce(lambda l,i: l if i in l else l+[i],lst,[])

  8. Александр Пискарёв

    Или так (наверное, побыстрее будет):
    result=[v for i,v in enumerate(src_lst) if v not in src_lst[:i]]

  9. Павел

    А попутно вопрос. Как убрать дубликаты из списка словарей красиво? set(), как я понимаю не работает же?

  10. Ivan Sagalaev

    Преобразуйте словари во что-нибудь hashable (например в tuple), удалите дубликаты, преобразуйте обратно.

  11. Андрей Иванов

    А вот что интересно. Можно ли на питоне иметь переменную большого размера, скажем длинный список, который физически находится на нескольких компьютерах в силу большого размера? Причём работать с ним в цикле, не заморачиваясь конкретным расположением данных. Короче, вперёд, в облака!

Добавить комментарий