Подтвердить что ты не робот

Преобразование списка в набор изменений порядка элементов

Недавно я заметил, что при преобразовании list для set порядок элементов изменяется и сортируется по символам.

Рассмотрим этот пример:

x=[1,2,20,6,210]
print x 
# [1, 2, 20, 6, 210] # the order is same as initial order

set(x)
# set([1, 2, 20, 210, 6]) # in the set(x) output order is sorted

Мои вопросы -

  1. Почему это происходит?
  2. Как я могу выполнять операции с сетами (особенно Set Difference), не теряя первоначальный порядок?
4b9b3361

Ответ 1

  • A set - неупорядоченная структура данных.

  • Не используйте set, а collections.OrderedDict:

    >>> a = collections.OrderedDict.fromkeys([1, 2, 20, 6, 210])
    >>> b = collections.OrderedDict.fromkeys([6, 20, 1])
    >>> collections.OrderedDict.fromkeys(x for x in a if x not in b)
    OrderedDict([(2, None), (210, None)])
    

    Обратите внимание, что порядок b не имеет значения, поэтому он может быть любым итерабельным, но должен быть итерабельным, который поддерживает тесты на членство O (1).

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

>>> a = [1, 2, 20, 6, 210]
>>> b = set([6, 20, 1])
>>> [x for x in a if x not in b]
[2, 210]

Это теряет порядок b, не позволяет быстро проверять членство на a и результат. Наборы позволяют быстро проверять членство, а списки сохраняют порядок. Если вам нужны обе эти функции в одной коллекции, используйте collections.OrderedDict.

Ответ 2

В Python 3.6 set() теперь должен сохранять порядок, но есть другое решение для Python 2 и 3:

>>> x = [1, 2, 20, 6, 210]
>>> sorted(set(x), key=x.index)
[1, 2, 20, 6, 210]

Ответ 3

Отвечая на ваш первый вопрос, множество - это структура данных, оптимизированная для операций над множествами. Как и математический набор, он не обеспечивает или не поддерживает какой-либо конкретный порядок элементов. Абстрактная концепция набора не обеспечивает порядок, поэтому реализация не обязательна. Когда вы создаете набор из списка, Python имеет право изменять порядок элементов для нужд внутренней реализации, которую он использует для набора, который способен эффективно выполнять операции над множествами.

Ответ 4

Как указано в других ответах, наборы представляют собой структуры данных (и математические концепции), которые не сохраняют порядок элементов -

Однако, используя комбинацию наборов и словарей, возможно, что вы можете добиться того, что захотите, попробуйте использовать эти фрагменты:

# save the element order in a dict:
x_dict = dict(x,y for y, x in enumerate(my_list) )
x_set = set(my_list)
#perform desired set operations
...
#retrieve ordered list from the set:
new_list = [None] * len(new_set)
for element in new_set:
   new_list[x_dict[element]] = element

Ответ 5

Основываясь на ответе Свена, я обнаружил, что использовал коллекции. Такой способ помог мне выполнить то, что вы хотите, и позволить мне добавить больше элементов в dict:

import collections

x=[1,2,20,6,210]
z=collections.OrderedDict.fromkeys(x)
z
OrderedDict([(1, None), (2, None), (20, None), (6, None), (210, None)])

Если вы хотите добавлять элементы, но все равно относитесь к ним как к набору, который вы можете просто сделать:

z['nextitem']=None

И вы можете выполнить операцию типа z.keys() на dict и получить набор:

z.keys()
[1, 2, 20, 6, 210]

Ответ 6

Реализация концепции наивысшего балла, приведенной выше, которая возвращает его в список:

def SetOfListInOrder(incominglist):
    from collections import OrderedDict
    outtemp = OrderedDict()
    for item in incominglist:
        outtemp[item] = None
    return(list(outtemp))

Протестировано (кратко) на Python 3.6 и Python 2.7.

Ответ 7

В случае, если у вас есть небольшое количество элементов в двух ваших начальных списках, для которых вы хотите выполнить операцию установки различий вместо использования collections.OrderedDict которая усложняет реализацию и делает ее менее читаемой, вы можете использовать:

# initial lists on which you want to do set difference
>>> nums = [1,2,2,3,3,4,4,5]
>>> evens = [2,4,4,6]
>>> evens_set = set(evens)
>>> result = []
>>> for n in nums:
...   if not n in evens_set and not n in result:
...     result.append(n)
... 
>>> result
[1, 3, 5]

Его временная сложность не так хороша, но она аккуратна и легко читается.

Ответ 8

Это потому, что множество является неупорядоченной структурой данных.

Для поддержания порядка вы можете сделать это следующим образом:

x=[1,2,3,20,6,210,50,20];
print(sorted(set(x),key=x.index));

Как вы увидите, вы можете выполнять операции над множествами, не теряя первоначального порядка.

Ответ 9

Вот простой способ сделать это:

x=[1,2,20,6,210]
print sorted(set(x))