python—将列表转换为集合会更改元素顺序

dy2hfwbg  于 2021-08-20  发布在  Java
关注(0)|答案(12)|浏览(887)

最近我注意到当我转换一个 listset 元素的顺序将更改,并按字符排序。
考虑这个例子:

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

我的问题是-
为什么会这样?
如何在不丢失初始顺序的情况下执行集合操作(尤其是集合差异)?

zmeyuzjn

zmeyuzjn1#

A. set 是无序的数据结构,因此不保留插入顺序。
这取决于你的要求。如果您有一个普通列表,并且希望在保留列表顺序的同时删除某些元素集,则可以使用列表理解来执行此操作:

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

如果需要支持快速成员资格测试和保留插入顺序的数据结构,可以使用python字典的键,从python 3.7开始,保证保留插入顺序:

>>> a = dict.fromkeys([1, 2, 20, 6, 210])
>>> b = dict.fromkeys([6, 20, 1])
>>> dict.fromkeys(x for x in a if x not in b)
{2: None, 210: None}
``` `b` 实际上不需要在这里订购-您可以使用 `set` 也注意 `a.keys() - b.keys()` 将设置的差异返回为 `set` ,因此它不会保留插入顺序。
在较旧版本的python中,可以使用 `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)])

dgjrabp2

dgjrabp22#

在python 3.6中, set() 现在我们应该遵守顺序,但是python 2和3还有另一个解决方案:

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

4ioopgfo3#

回答第一个问题,集合是为集合操作而优化的数据结构。和数学集合一样,它不强制或维持元素的任何特定顺序。集合的抽象概念不强制执行顺序,因此不需要实现。从列表创建集合时,python可以根据集合内部实现的需要自由更改元素的顺序,从而能够高效地执行集合操作。

v8wbuo2f

v8wbuo2f4#

通过以下功能删除重复项并保留顺序

def unique(sequence):
    seen = set()
    return [x for x in sequence if not (x in seen or seen.add(x))]

如何在python中保留顺序的同时从列表中删除重复项

hi3rlvi2

hi3rlvi25#

在数学中,有集合和有序集合(OSET)。
集合:唯一元素的无序容器(已实现)
oset:唯一元素的有序容器(未实现)
在python中,只有集合是直接实现的。我们可以用常规dict键(3.7+)模拟操作系统。
鉴于

a = [1, 2, 20, 6, 210, 2, 1]
b = {2, 6}

代码

oset = dict.fromkeys(a).keys()

# dict_keys([1, 2, 20, 6, 210])

演示
删除复制,保留插入顺序。

list(oset)

# [1, 2, 20, 6, 210]

在dict键上设置类似的操作。

oset - b

# {1, 20, 210}

oset | b

# {1, 2, 5, 6, 20, 210}

oset & b

# {2, 6}

oset ^ b

# {1, 5, 20, 210}

细节
注:无序结构并不排除有序元素。相反,维持秩序并不能得到保证。例子:

assert {1, 2, 3} == {2, 3, 1}                    # sets (order is ignored)
assert [1, 2, 3] != [2, 3, 1]                    # lists (order is guaranteed)

人们可能会高兴地发现,列表和多集(mset)是两种更有趣的数学数据结构:
列表:允许复制的有序元素容器(已实现)
mset:允许复制的无序元素容器(未实现)*
总结

Container | Ordered | Unique | Implemented
----------|---------|--------|------------
set       |    n    |    y   |     y
oset      |    y    |    y   |     n
list      |    y    |    n   |     y
mset      |    n    |    n   |     n*
  • 可以使用间接模拟多集 collections.Counter() ,多重性(计数)的类似于dict的Map。
mznpcxlj

mznpcxlj6#

如其他答案所示,集合是不保持元素顺序的数据结构(和数学概念)——
但是,通过使用集合和字典的组合,您可以实现您想要的任何功能-尝试使用以下代码段:


# 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
rxztt3cl

rxztt3cl7#

您可以删除重复的值,并使用一行代码python 3.8.2保持插入的列表顺序

mylist = ['b', 'b', 'a', 'd', 'd', 'c']

results = list({value:"" for value in mylist})

print(results)

>>> ['b', 'a', 'd', 'c']

results = list(dict.fromkeys(mylist))

print(results)

>>> ['b', 'a', 'd', 'c']
eqzww0vc

eqzww0vc8#

基于sven的回答,我发现使用collections.ordereddict这样的工具帮助我实现了你想要的,并允许我在目录中添加更多项目:

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

您可以在dict上执行类似z.keys()的操作,并获取集合:

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

py49o6xq9#

上述最高分数概念的实现,将其带回列表:

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

在Python3.6和Python2.7上测试(简要)。

nwo49xxi

nwo49xxi10#

如果在两个初始列表中有少量元素,您希望对其执行“设置差异”操作,而不是使用 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]

它的时间复杂度不是很好,但它很简洁易读。

efzxgjgh

efzxgjgh11#

有趣的是,人们总是用“现实世界问题”来开理论科学定义的玩笑。
如果set有顺序,首先需要解决以下问题。如果列表中有重复的元素,那么将其转换为集合时的顺序应该是什么?如果我们合并两组,顺序是什么?如果我们在同一元素上相交两个顺序不同的集合,其顺序是什么?
另外,set在搜索特定的键时要快得多,这在set操作中非常好(这就是为什么需要set,而不是list)。
如果你真的关心索引,就把它列为一个列表。如果仍要对多个列表中的元素执行set操作,最简单的方法是为每个列表创建一个字典,其中包含集合中相同的键以及包含原始列表中键的所有索引的list值。

def indx_dic(l):
    dic = {}
    for i in range(len(l)):
        if l[i] in dic:
            dic.get(l[i]).append(i)
        else:
            dic[l[i]] = [i]
    return(dic)

a = [1,2,3,4,5,1,3,2]
set_a  = set(a)
dic_a = indx_dic(a)

print(dic_a)

# {1: [0, 5], 2: [1, 7], 3: [2, 6], 4: [3], 5: [4]}

print(set_a)

# {1, 2, 3, 4, 5}
uqzxnwby

uqzxnwby12#

下面是一个简单的方法:

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

相关问题