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

2024-11-28 08:37:00
admin
原创
4
摘要:问题描述:最近我注意到,当我将 转换为 时,元素的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...

问题描述:

最近我注意到,当我将 转换为 时,元素的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. 如何在不丢失初始顺序的情况下进行集合运算(尤其是集合差分)?


解决方案 1:

  1. Aset是无序数据结构,因此它不保留插入顺序。

  2. 这取决于您的要求。如果您有一个普通列表,并且想要删除一些元素集同时保留列表的顺序,则可以使用列表推导来执行此操作:

>>> 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。请注意,a.keys() - b.keys()将集合差异返回为 a 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)])

解决方案 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:

通过以下函数删除重复项并保留顺序

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

如何在 Python 中保留列表中的顺序并删除重复项

解决方案 4:

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

解决方案 5:

在数学中,有集合和有序集(oset)。

  • 集合:唯一元素的无序容器(已实现)

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

在 Python 中,仅直接实现了集合。我们可以使用常规字典键(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]

对字典键进行类似集合的操作。

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()* 可以使用类似于字典的多重性(计数)映射来间接模拟多重集。

解决方案 6:

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

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


结果 = 列表({值:“” 表示 mylist 中的值})

打印(结果)

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

结果 = 列表(dict.fromkeys(mylist))

打印(结果)

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

解决方案 7:

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

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

# 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

解决方案 8:

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

您还可以对字典执行类似 z.keys() 的操作并获取集合:

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

解决方案 9:

回答晚了,但您可以使用 Pandas、pd.Series 来转换列表,同时保留顺序:

import pandas as pd
x = pd.Series([1, 2, 20, 6, 210, 2, 1])
print(pd.unique(x))

输出:
array([ 1, 2, 20, 6, 210])

适用于字符串列表

x = pd.Series(['c', 'k', 'q', 'n', 'p','c', 'n'])
print(pd.unique(x))

输出
['c' 'k' 'q' 'n' 'p']

解决方案 10:

一个更简单的方法是创建一个空列表,比如说“unique_list”,用于从原始列表中添加唯一元素,例如:

unique_list=[]

for i in original_list:
    if i not in unique_list:
        unique_list.append(i)
    else:
        pass

这将为您提供所有独特的元素并保持秩序。

解决方案 11:

我喜欢下面的解决方案,因为它很简洁。它使用PEP 448 – 附加解包泛化,它在 Python 3.5+ 中有效,并且依赖于dict保留插入顺序(CPython 3.6+ 或 Python 3.7+)。

def unique(sequence):
    return [*dict.fromkeys(sequence)]

此外,对于较大的序列,它似乎比检查集合成员资格更快:

from timeit import timeit


def unique(sequence):
    return [*dict.fromkeys(sequence)]


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


a_large_list = [*range(100)] + [*range(10)]

assert set_unique(a_large_list) == unique(a_large_list)
print(
    timeit('set_unique(a_large_list)', globals=globals(), number=100_000)
    / timeit('unique(a_large_list)', globals=globals(), number=100_000)
)  # 2.379634026726176 times faster!

解决方案 12:

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

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

解决方案 13:

如果您想要对两个初始列表中的少量元素进行集合差异运算,而不是使用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]

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

解决方案 14:

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

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

另外,集合在搜索特定键时速度更快,这在集合操作中非常好(这就是为什么需要集合而不是列表的原因)。

如果您真的在乎索引,只需将其保留为列表即可。如果您仍想对多个列表中的元素执行集合操作,最简单的方法是为每个列表创建一个字典,其中包含集合中的相同键以及包含原始列表中所有键索引的列表值。

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}

解决方案 15:

我们可以使用collections.Counter来实现这一点:

# tested on python 3.7
>>> from collections import Counter
>>> lst = ["1", "2", "20", "6", "210"]

>>> for i in Counter(lst):
>>>     print(i, end=" ")
1 2 20 6 210 

>>> for i in set(lst):
>>>     print(i, end=" ")
20 6 2 1 210

解决方案 16:

如果需要,您可以删除重复的值并保持列表的插入顺序

lst = [1,2,1,3]
new_lst = []

for num in lst :
    if num not in new_lst :
        new_lst.append(num)

# new_lst = [1,2,3]

如果您想要的是“顺序”,请不要使用“集合”来删除重复项,

使用集合进行搜索,即

列表中的 x

需要 O(n) 时间

,而

集合中的 x

需要 O(1) 时间 *大多数情况下

解决方案 17:

这是一个简单的方法:

x=[1,2,20,6,210]
print sorted(set(x))
相关推荐
  为什么项目管理通常仍然耗时且低效?您是否还在反复更新电子表格、淹没在便利贴中并参加每周更新会议?这确实是耗费时间和精力。借助软件工具的帮助,您可以一目了然地全面了解您的项目。如今,国内外有足够多优秀的项目管理软件可以帮助您掌控每个项目。什么是项目管理软件?项目管理软件是广泛行业用于项目规划、资源分配和调度的软件。它使项...
项目管理软件   642  
  引言在当今快速变化的科技市场中,企业要想保持竞争力,就必须具备高效的产品开发流程。小米作为一家以创新驱动的科技公司,其集成产品开发(IPD)流程在业界颇受关注。其中,技术路线图规划作为IPD流程的核心环节,对于确保产品技术领先、满足市场需求以及实现长期战略目标至关重要。本文将深入探讨小米IPD流程中的技术路线图规划,分...
华为IPD是什么   0  
  在当今快速变化的商业环境中,项目管理的高效执行是企业成功的关键。为了应对日益复杂的产品开发挑战,企业纷纷寻求将产品开发流程(Product Development Process, PDCP)与集成产品开发(Integrated Product Development, IPD)流程相结合的策略,以实现更高效、更协同的...
IPD管理   0  
  在当今竞争激烈的市场环境中,提高客户满意度是企业持续发展和成功的关键。为了实现这一目标,企业需要不断优化其产品开发和管理流程。IPD(Integrated Product Development,集成产品开发)流程图作为一种高效的项目管理工具,能够帮助企业实现跨部门协作、优化资源配置,并最终提升客户满意度。本文将深入探...
IPD流程是谁发明的   0  
  在项目管理领域,集成产品开发(IPD, Integrated Product Development)流程被视为提升项目成功率的关键框架。IPD通过其系统化的方法,将产品开发过程中的各个阶段紧密连接,确保从概念到市场的每一步都经过深思熟虑和高效执行。本文将深入探讨IPD流程的六个核心阶段如何深刻影响项目成功,并为项目管...
IPD流程中CDCP   0  
热门文章
项目管理软件有哪些?
云禅道AD
禅道项目管理软件

云端的项目管理软件

尊享禅道项目软件收费版功能

无需维护,随时随地协同办公

内置subversion和git源码管理

每天备份,随时转为私有部署

免费试用