将列表转换为集更改元素顺序

时间:2012-03-20 18:19:40

标签: python set

最近我注意到,当我将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. 如何在不丢失初始订单的情况下进行设置操作(尤其是设置差异)?

12 个答案:

答案 0 :(得分:77)

  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)成员资格测试的可迭代。

  3. 编辑:上面的答案假定您希望能够对所有正在发生的集合执行(有序)集合操作,特别是对前一个集合操作的结果。如果没有必要,您可以简单地为某些集合使用列表,为其他集合使用集合,例如

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

答案 1 :(得分:26)

在Python 3.6中,tableView.dequeueReusableCell(withIdentifier: "customCell",for: indexPath) as! CustomCell 现在应该保持顺序,但还有另一个Python 2和3的解决方案:

set()

答案 2 :(得分:14)

回答第一个问题,集合是针对集合操作优化的数据结构。像数学集一样,它不强制执行或维护元素的任何特定顺序。集合的抽象概念不强制执行顺序,因此不需要实现。当您从列表创建集合时,Python可以自由地更改元素的顺序,以满足它用于集合的内部实现的需要,这可以有效地执行集合操作。

答案 3 :(得分:3)

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

但是,通过使用集合和词典的组合,您可以实现所需的监视器 - 尝试使用这些片段:

# 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

答案 4 :(得分:3)

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

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

check this link

答案 5 :(得分:1)

在Sven的回答基础上,我发现使用collections.OrderedDict这样帮助我完成了你想要的东西,并允许我在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

你可以在dict上执行类似z.keys()的操作并获取set:

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

答案 6 :(得分:1)

上面最高分概念的实现将其带回到列表中:

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 :(得分:1)

在数学中,有setsordered sets(osets)。

  • set :唯一元素的无序容器(已实现)
  • oset :一个唯一元素的有序容器(未实现)

在Python中,仅直接实现集合。我们可以使用常规字典键(3.7+)模拟osets。

给出

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}

人们可能很高兴发现listmultiset(mset)是另外两个引人入胜的数据结构:

  • list :允许重复的元素的有序容器(已实现)
  • mset :元素的无序容器,允许重复(未实现)*

*可以使用collections.Counter()multiplicities(计数)的类似字典的映射)间接模拟多集。

答案 8 :(得分:0)

如果要在其两个初始列表中进行设置差值运算的元素数量较少,则可以使用以下方法代替使用collections.OrderedDict,该方法会使实现变得复杂并使可读性降低,请使用: / p>

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

它的时间复杂度不是很好,但是它整洁且易于阅读。

答案 9 :(得分:0)

有趣的是,人们总是使用“现实世界中的问题”来开玩笑以解释理论科学中的定义。

如果集合有顺序,则首先需要弄清楚以下问题。 如果列表中有重复的元素,那么将其变成集合时的顺序应该是什么?如果我们将两个集合并集,顺序是什么?如果在同一元素上以不同顺序相交的两个集合相交,顺序是什么?

此外,set在搜索特定键方面要快得多,这对set操作非常有用(这就是为什么需要set而不是list的原因)。

如果您真的在乎索引,只需将其保留为列表即可。如果仍要对许多列表中的元素进行设置操作,最简单的方法是为每个列表创建一个字典,该列表中的集合具有相同的键以及包含原始列表中所有键索引的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}

答案 10 :(得分:0)

您可以删除重复的值,并使用一行代码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']

答案 11 :(得分:-8)

这是一种简单的方法:

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