2012-03-20 88 views
42

最近我注意到,当我转换列表来设置顺序或元素更改并按字符排序。设置更改元素顺序?

考虑这个例子:

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. 如何在不丢失初始订单的情况下设置操作(尤其是设置差异)?
+5

为什么不想失去最初的顺序,特别是如果你正在执行set操作? “秩序”对集合来说是一个无意义的概念,不仅仅在Python中,而且在数学中。 – 2012-03-20 18:48:51

+46

@KarlKnechtel - 是“订单对于数学中的集合是一个无意义的概念”,但是我遇到了现实世界的问题:) – 2012-03-21 11:32:55

回答

50
  1. set是一个无序的数据结构。

  2. 不要使用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

+0

无对象花费16个字节。如果只有一个默认的OrderedSet()。 :( – Sean 2017-11-06 08:43:48

13

回答你的第一个问题,set是一个针对集合操作进行优化的数据结构,并且像数学集合一样,它不强制/维护元素的任何特定顺序。集合的抽象概念不强制执行顺序,所以不执行。当你从一个列表创建一个集合时,python会自由地改变元素的顺序,以满足它为一个集合所使用的内部实现的需要,这个集合能够高效地执行集合操作。

3

在其他的答案表示,集数据结构(和数学概念)不保留元素顺序 -

然而,通过使用组和字典的结合,这是可能的,你可以实现wathever你想要的 - 尝试使用这些内容摘要:在埃里克森的回答

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

大厦,我发现使用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 

而且你可以像ž执行操作。键()的字典,并获得集:

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

您需要执行'list(z.keys())'获取列表输出。 – jxn 2017-12-15 23:09:10

+0

in Python 3,yes。不在Python 2中,但我应该指定。 – jimh 2017-12-16 00:00:06

-5

这里有一个简单的方法来做到这一点:

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

这不会保留必要的顺序 – 2016-11-15 16:47:18

+1

只有在输入排序后,这个答案才是正确的 – msudder 2016-12-20 17:27:50

10

在Python 3.6,set()现在应该维持秩序,但还有另一种Python 2和3的解决方案:

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

关于订单保存的两个注意事项:只有Python 3.6版本,甚至在那里,它被认为是一个实现细节,所以不要依赖它。除此之外,你的代码是非常效率低下,因为每次调用x.index时,都会执行线性搜索,如果您的系统复杂度很高,那么没有理由首先使用set。 – 2016-12-29 11:56:03

+9

@ThijsvanDien这是错误的,'' set()'在Python 3.6中没有排序,甚至没有作为实现细节,你正在考虑'dict' – 2017-08-09 12:06:14

+0

@Chris_Rands我站得更正了;它们似乎被排序,而不是保持插入o刻申。无论哪种方式:实现细节。 – 2017-08-09 17:47:02