В Python, каков самый быстрый алгоритм для удаления дубликатов из списка так, чтобы все элементы были уникальны *при сохранении порядка*? [дубликат]

Добавлен ответ @ jaredpar, вот что я использую для проверки интерфейсов:

public static bool IsImplementerOfRawGeneric(this Type type, Type toCheck)
{
    if (toCheck.GetTypeInfo().IsClass)
    {
        return false;
    }

    return type.GetInterfaces().Any(interfaceType =>
    {
        var current = interfaceType.GetTypeInfo().IsGenericType ?
                    interfaceType.GetGenericTypeDefinition() : interfaceType;
        return current == toCheck;
    });
}

public static bool IsSubTypeOfRawGeneric(this Type type, Type toCheck)
{
    return type.IsInterface ?
          IsImplementerOfRawGeneric(type, toCheck)
        : IsSubclassOfRawGeneric(type, toCheck);
}

Пример:

Console.WriteLine(typeof(IList<>).IsSubTypeOfRawGeneric(typeof(IList<int>))); // true
41
задан J Miller 18 September 2008 в 22:49
поделиться

22 ответа

def unique(items):
    found = set([])
    keep = []

    for item in items:
        if item not in found:
            found.add(item)
            keep.append(item)

    return keep

print unique([1, 1, 2, 'a', 'a', 3])
31
ответ дан Terhorst 23 September 2019 в 14:57
поделиться

Одна передача.

a = [1,1,'a','b','c','c']

new_list = []
prev = None

while 1:
    try:
        i = a.pop(0)
        if i != prev:
            new_list.append(i)
        prev = i
    except IndexError:
        break
-2
ответ дан Sergey Stolyarov 23 September 2019 в 14:57
поделиться

Я не сделал никаких тестов, но один возможный алгоритм мог бы быть должен создать второй список и выполнить итерации через первый список. Если объект не находится во втором списке, добавьте его к второму списку.

x = [1, 1, 2, 'a', 'a', 3]
y = []
for each in x:
    if each not in y:
        y.append(each)
-2
ответ дан Matthew Schinckel 23 September 2019 в 14:57
поделиться

= [1,2,3,4,5,7,7,8,8,9,9,3,45]

определение, уникальное (l):

ids={}
for item in l:
    if not ids.has_key(item):
        ids[item]=item
return  ids.keys()

печатают

, печатают уникальный (a)

, элементы Вставки----------------------------

возьмут тету (n) получение, если элемент выйдет или не займет постоянное время, тестируя все объекты, то возьмет также тету (n), таким образом, мы видим, что это решение возьмет тету (n), Принимают во внимание что словарь в Python, реализованном хэш-таблицей

-2
ответ дан aboSamoor 23 September 2019 в 14:57
поделиться

Я не знаю, быстр ли этот или нет, но по крайней мере это просто.

Просто, преобразуйте его сначала в набор и с другой стороны в список

def unique(container):
  return list(set(container))
-1
ответ дан Franck Mesirard 23 September 2019 в 14:57
поделиться
>>> x=[1,1,2,'a','a',3]
>>> y = [ _x for _x in x if not _x in locals()['_[1]'] ]
>>> y
[1, 2, 'a', 3]


"местные жители () [' _ [1]']" "секретное название" создаваемого списка.

-1
ответ дан Kevin Little 23 September 2019 в 14:57
поделиться
>>> def unique(list):
...   y = []
...   for x in list:
...     if x not in y:
...       y.append(x)
...   return y
0
ответ дан etchasketch 23 September 2019 в 14:57
поделиться

При вынимании пустого списка от вызова для установки () в ответе Terhost, Вы получаете немного повышения скорости.

Изменение: найденный = набор ([])
к: найденный = набор ()

Однако Вам не нужен набор вообще.

def unique(items):
    keep = []

    for item in items:
        if item not in keep:
            keep.append(item)

    return keep

Используя timeit я получил эти результаты:

с набором ([]) - 4.97210427363
с набором () - 4.65712377445
без набора - 3.44865284975

0
ответ дан user18695 23 September 2019 в 14:57
поделиться

У меня нет опыта с Python, но алгоритм должен был бы отсортировать список, затем удалить дубликаты (по сравнению с предыдущими объектами в списке), и наконец найти положение в новом списке путем сравнения старому списку.

Более длинный ответ: http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/52560

0
ответ дан solinent 23 September 2019 в 14:57
поделиться

Здесь существуют некоторые большие, эффективные решения. Однако для любого не обеспокоенного абсолютом, самым эффективным O(n) решение, я пошел бы с простой остротой O(n^2*log(n)) решение:

def unique(xs):
    return sorted(set(xs), key=lambda x: xs.index(x))

или более эффективный с двумя лайнерами O(n*log(n)) решение:

def unique(xs):
    positions = dict((e,pos) for pos,e in reversed(list(enumerate(xs))))
    return sorted(set(xs), key=lambda x: positions[x])
1
ответ дан Eli Courtwright 23 September 2019 в 14:57
поделиться

has_key в Python является O (1). Вставка и извлечение от хеша также O (1). Циклы через n объекты дважды, таким образом, O (n).

def unique(list):
  s = {}
  output = []
  for x in list:
    count = 1
    if(s.has_key(x)):
      count = s[x] + 1

    s[x] = count
  for x in list:
    count = s[x]
    if(count > 0):
      s[x] = 0
      output.append(x)
  return output
1
ответ дан etchasketch 23 September 2019 в 14:57
поделиться

Дубликаты должны обязательно быть в списке во-первых? Нет никаких издержек до поиска элементов, но существует немного больше служебное в добавляющих элементах (хотя издержки должны быть O (1)).

>>> x  = []
>>> y = set()
>>> def add_to_x(val):
...     if val not in y:
...             x.append(val)
...             y.add(val)
...     print x
...     print y
... 
>>> add_to_x(1)
[1]
set([1])
>>> add_to_x(1)
[1]
set([1])
>>> add_to_x(1)
[1]
set([1])
>>> 
2
ответ дан Jason Baker 23 September 2019 в 14:57
поделиться

O (n), если dict является хешем, O (nlogn), если dict является деревом, и простой, зафиксированный. Благодаря Matthew для предложения. Извините я не знаю базовые типы.

def unique(x):    
  output = []
  y = {}
  for item in x:
    y[item] = ""

  for item in x:
    if item in y:
      output.append(item)

  return output
1
ответ дан Wesley Tarle 23 September 2019 в 14:57
поделиться

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

   # remove duplicates...
   def unique(my_list):
       return [x for x in my_list if x not in locals()['_[1]'].__self__]

Редактирование: я удалил "сам", и это работает над Mac OS X, Python 2.5.1.

_ [1] является "секретной" ссылкой Python на новый список. Вышеупомянутое, конечно, немного грязно, но Вы могли адаптировать его, соответствуют Вашим потребностям по мере необходимости. Например, можно на самом деле записать функцию, которая возвращает ссылку на понимание; это посмотрело бы больше как:

return [x for x in my_list if x not in this_list()]
<час>
3
ответ дан Jake 23 September 2019 в 14:57
поделиться

Взятый от http://www.peterbe.com/plog/uniqifiers-benchmark

def f5(seq, idfun=None):  
    # order preserving 
    if idfun is None: 
        def idfun(x): return x 
    seen = {} 
    result = [] 
    for item in seq: 
        marker = idfun(item) 
        # in old Python versions: 
        # if seen.has_key(marker) 
        # but in new ones: 
        if marker in seen: continue 
        seen[marker] = 1 
        result.append(item) 
    return result
4
ответ дан ctcherry 23 September 2019 в 14:57
поделиться

Обязательное основанное на генераторе изменение:

def unique(seq):
  seen = set()
  for x in seq:
    if x not in seen:
      seen.add(x)
      yield x
7
ответ дан Constantin 23 September 2019 в 14:57
поделиться

Острота:

new_list = reduce(lambda x,y: x+[y][:1-int(y in x)], my_list, [])
5
ответ дан Tyler 23 September 2019 в 14:57
поделиться

Это - самый быстрый оперативный метод, который я нашел (принятие значительной доли дубликатов):

def unique(l):
    s = set(); n = 0
    for x in l:
        if x not in s: s.add(x); l[n] = x; n += 1
    del l[n:]

Это на 10% быстрее, чем реализация Allen, на которой это базируется (синхронизировано с timeit.repeat, JIT, скомпилированный психо). Это сохраняет первую инстанцию любого дубликата.

бесконечность Рептона: мне было бы интересно, если Вы могли бы подтвердить мои синхронизации.

9
ответ дан James Hopkin 23 September 2019 в 14:57
поделиться

То, что будет самым быстрым, зависит от того, какой процент Вашего списка является дубликатами. Если это будут почти все дубликаты с немногими уникальными объектами, то создавание нового списка, вероятно, будет быстрее. Если это будут главным образом уникальные объекты, то удалять их из исходного списка (или копия) будет быстрее.

Вот один для изменения списка на месте:

def unique(items):
  seen = set()
  for i in xrange(len(items)-1, -1, -1):
    it = items[i]
    if it in seen:
      del items[i]
    else:
      seen.add(it)

Итерация назад по индексам гарантирует, что удаление объектов не влияет на повторение.

13
ответ дан Allen 23 September 2019 в 14:57
поделиться

Вот быстрое решение до сих пор (для следующего входа):

def del_dups(seq):
    seen = {}
    pos = 0
    for item in seq:
        if item not in seen:
            seen[item] = True
            seq[pos] = item
            pos += 1
    del seq[pos:]

lst = [8, 8, 9, 9, 7, 15, 15, 2, 20, 13, 2, 24, 6, 11, 7, 12, 4, 10, 18, 
       13, 23, 11, 3, 11, 12, 10, 4, 5, 4, 22, 6, 3, 19, 14, 21, 11, 1, 
       5, 14, 8, 0, 1, 16, 5, 10, 13, 17, 1, 16, 17, 12, 6, 10, 0, 3, 9, 
       9, 3, 7, 7, 6, 6, 7, 5, 14, 18, 12, 19, 2, 8, 9, 0, 8, 4, 5]
del_dups(lst)
print(lst)
# -> [8, 9, 7, 15, 2, 20, 13, 24, 6, 11, 12, 4, 10, 18, 23, 3, 5, 22, 19, 14, 
#     21, 1, 0, 16, 17]

Поиск по словарю немного быстрее тогда один набора в Python 3.

14
ответ дан jfs 23 September 2019 в 14:57
поделиться

Используя:

lst = [8, 8, 9, 9, 7, 15, 15, 2, 20, 13, 2, 24, 6, 11, 7, 12, 4, 10, 18, 13, 23, 11, 3, 11, 12, 10, 4, 5, 4, 22, 6, 3, 19, 14, 21, 11, 1, 5, 14, 8, 0, 1, 16, 5, 10, 13, 17, 1, 16, 17, 12, 6, 10, 0, 3, 9, 9, 3, 7, 7, 6, 6, 7, 5, 14, 18, 12, 19, 2, 8, 9, 0, 8, 4, 5]

И использование timeit модуля:

$ python -m timeit -s 'import uniquetest' 'uniquetest.etchasketch(uniquetest.lst)'

И так далее для различных других функций (который я назвал в честь их плакатов), у меня есть следующие результаты (на моем первом поколении Intel MacBook Pro):

Allen:                  14.6 µs per loop [1]
Terhorst:               26.6 µs per loop
Tarle:                  44.7 µs per loop
ctcherry:               44.8 µs per loop
Etchasketch 1 (short):  64.6 µs per loop
Schinckel:              65.0 µs per loop
Etchasketch 2:          71.6 µs per loop
Little:                 89.4 µs per loop
Tyler:                 179.0 µs per loop

[1] Примечание, что Allen изменяет список на месте †“, я полагаю, что это скосило время в этом timeit, модуль выполняет код 100000 раз, и 99999 из них со списком простофили меньше.

<час>

Сводка : простая реализация с победами наборов над запутывающими остротами:-)

18
ответ дан mkierc 23 September 2019 в 14:57
поделиться

Однострочный текст на месте для этого:

>>> x = [1, 1, 2, 'a', 'a', 3]
>>> [ item for pos,item in enumerate(x) if x.index(item)==pos ]
[1, 2, 'a', 3]
4
ответ дан 27 November 2019 в 00:13
поделиться
Другие вопросы по тегам:

Похожие вопросы: