将列表转换为集合会改变元素顺序
- 2024-11-28 08:37:00
- admin 原创
- 5
问题描述:
最近我注意到,当我将 转换为 时,元素的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:
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。请注意,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 中,对于 Python 2 和 3 还有另一种解决方案:set()
现在应该保留顺序,但是
>>> 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))
- 2024年20款好用的项目管理软件推荐,项目管理提效的20个工具和技巧
- 2024年开源项目管理软件有哪些?推荐5款好用的项目管理工具
- 项目管理软件有哪些?推荐7款超好用的项目管理工具
- 项目管理软件哪个最好用?盘点推荐5款好用的项目管理工具
- 项目管理软件有哪些最好用?推荐6款好用的项目管理工具
- 项目管理软件有哪些,盘点推荐国内外超好用的7款项目管理工具
- 2024年常用的项目管理软件有哪些?推荐这10款国内外好用的项目管理工具
- 2024项目管理软件排行榜(10类常用的项目管理工具全推荐)
- 项目管理软件排行榜:2024年项目经理必备5款开源项目管理软件汇总
- 项目管理必备:盘点2024年13款好用的项目管理软件