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

Python 将列表转换为集合会更改元素顺序,python,set,Python,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 我的问题是- 为什么会这样 如何在不丢失初始顺序的情况下执行集合操作(尤其是集合差异) A是无

最近我注意到,当我将
列表
转换为
集合
时,元素的顺序发生了变化,并按字符排序

考虑这个例子:

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
我的问题是-

  • 为什么会这样
  • 如何在不丢失初始顺序的情况下执行集合操作(尤其是集合差异)
  • A是无序的数据结构,因此它不保留插入顺序

  • 这取决于你的要求。如果您有一个普通列表,并且希望在保留列表顺序的同时删除某些元素集,则可以使用列表理解来执行此操作:

    >>> 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
    实际上不需要在这里订购–您也可以使用
    集合
    。请注意,
    a.keys()-b.keys()
    将设置的差异返回为
    set
    ,因此它不会保留插入顺序

    在较旧版本的Python中,您可以改为使用:


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

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

    但是,通过使用集合和字典的组合,您可以实现您想要的任何功能-尝试使用以下代码段:

    # 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
    

    基于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]
    

    下面是一个简单的方法:

    x=[1,2,20,6,210]
    print sorted(set(x))
    
    在Python3.6中,
    set()
    现在应该保持顺序,但是Python2和3还有另一个解决方案:

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

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

    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上测试(简要)。

    如果您的两个初始列表中有少量元素要对其执行set difference操作,而不是使用
    集合。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]
    
    

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

    通过下面的函数删除重复项并保持顺序

    def unique(sequence):
        seen = set()
        return [x for x in sequence if not (x in seen or seen.add(x))]
    
    在数学中,有和(oset)

    • 集合:唯一元素的无序容器(已实现)
    • oset:唯一元素的有序容器(未实现)
    在Python中,只有集合是直接实现的。我们可以用常规dict键()模拟操作系统

    给定的

    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)
    

    人们可能会高兴地发现a和(mset)是两种更有趣的数学数据结构:

    • 列表:允许复制的有序元素容器(已实现)
    • mset:允许复制的无序元素容器(未实现)*
    总结


    *一个多重集可以间接地用集合。计数器()来模拟。,这是一种类似于dict的(计数)映射。

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

    如果set有顺序,首先需要解决以下问题。 如果列表中有重复的元素,那么将其转换为集合时的顺序应该是什么?如果我们合并两组,顺序是什么?如果我们在同一元素上相交两个顺序不同的集合,其顺序是什么

    另外,set在搜索特定的键时要快得多,这在set操作中非常好(这就是为什么需要set,而不是list)

    如果你真的关心索引,就把它列为一个列表。如果仍要对多个列表中的元素执行set操作,最简单的方法是为每个列表创建一个字典,其中包含集合中相同的键以及包含原始列表中键的所有索引的list值

    def indx_dic(l):
    dic={}
    对于范围内的i(len(l)):
    如果dic中的l[i]:
    dic.get(l[i]).追加(i)
    其他:
    dic[l[i]]=[i]
    返回(dic)
    a=[1,2,3,4,5,1,3,2]
    集合a=集合(a)
    dic_a=indx_dic(a)
    打印(dic_a)
    # {1: [0, 5], 2: [1, 7], 3: [2, 6], 4: [3], 5: [4]}
    打印(设置a)
    # {1, 2, 3, 4, 5}
    
    您可以删除重复的值,并使用一行代码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'] mylist=['b','b','a','d','d','c'] 结果=列表({value:“”表示mylist}中的值) 打印(结果) >>>['b','a','d','c'] 结果=列表(dict.fromkeys(mylist)) 打印(结果)
    >>>['b','a','d','c']@KarlKnechtel-Yes“顺序对于集合来说是一个毫无意义的概念……在数学中”,但我有现实世界的问题:)关于CPython 3.6+
    unique=list(dict.fromkeys([1,2,1]).keys()
    。这是因为
    dict
    s现在保留插入顺序。这不一定保留顺序。关于顺序p的两个注释
    assert [1, 2, 3] != [2, 3, 1]                    # lists (order is guaranteed)
    
    Container | Ordered | Unique | Implemented
    ----------|---------|--------|------------
    set       |    n    |    y   |     y
    oset      |    y    |    y   |     n
    list      |    y    |    n   |     y
    mset      |    n    |    n   |     n*  
    
    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']