将集合转换为列表时,什么决定了项目顺序?

2024-04-19 08:45:06 发布

您现在位置:Python中文网/ 问答频道 /正文

我知道有几个类似的问题,但我还没有找到一个能说明我想知道什么的问题。如果这是重复的,请指出

所以我知道Python中的set是一个无序的集合,而list可以排序。我想知道的是,当列表从集合转换时,是什么决定了列表项的顺序

即使一个集合“技术上”没有排序(我猜这只是意味着你不能像处理序列类型那样与它交互),但在打印集合时,仍然存在一种顺序,例如,必须先打印一个项目、第二个项目、第三个项目等等。这种逻辑需要存在。但它甚至更进一步。例如,如果您声明两个处于“加扰”状态的集合,其中包含可排序的项,那么在执行它们时,它们的表示不仅会排序,而且两个“加扰”集合的联合也会返回一个“排序”集合:

a = {2, 3, 1}
a
# >>> {1, 2, 3}
b = {7, 4, 5}
b
# >>> {4, 5, 7}

a|b  
# >>> {1, 2, 3, 4, 5, 7} 
b|a
# >>> {1, 2, 3, 4, 5, 7}

此外,当您add将新项目添加到集合并打印集合时,新项目将显示在正确的位置,即集合排序后的位置:

b.add(6)
b
# >>> {4, 5, 6, 7}

这就引出了我的问题。如果将集合转换为列表,则必须确定集合中的每个项目在新列表中的位置。但显然并不是在执行集合时确定项目打印顺序的相同逻辑,这正是我天真的想法。虽然list(a)list(b)甚至list(a|b)所有按集合表示方式排序的返回列表,但对于以下集合(以及其所有置换),出于某种原因,情况并非如此:

list(a), list(b), list(a|b)
# >>> ([1, 2, 3], [4, 5, 6, 7], [1, 2, 3, 4, 5, 6, 7])
c = {3, 4, 9}  # or {3, 9, 4}, {4, 3, 9} and so on...
c
# >>> {3, 4, 9}
list(c)  
# >>> [9, 3, 4]

为什么呢?为什么确定集合表示的顺序的逻辑与确定集合转换为列表时集合中每个项的位置的逻辑不同

我又尝试了几个不同值的集合,在我看来,当集合的表示顺序和集合列表的顺序相同时,这似乎是完全随机的:

# for this set of numbers, the logic is different
d = {3, 4, 11}
d
# >>> {3, 4, 11}
list(d)  
# >>> [11, 3, 4]

# in this case, permutations also result in different sorting of the list
d = {11, 4, 3}
d
# >>> {3, 4, 11}
list(d)  
# >>> [3, 11, 4]

# for this set, the logic appears to be the same again
e = {3, 4, 13}  # or any of its permutations
e
# >>> {3, 4, 13}
list(e)
# >>> [3, 4, 13]

确定列表顺序和调用print(set)的逻辑似乎是相同的:

list(d)  
# >>> [3, 11, 4]
print(d)
# >>> {3, 11, 4}

所以我猜只要你对集合做点什么,就会应用不同的排序逻辑。当然,除非您创建联合:

print(c, d, c|d, list(c|d))
# >>> {9, 3, 4} {3, 11, 4} {3, 4, 9, 11} [3, 4, 9, 11]
f = {3, 4, 9, 11}
f
# >>> {3, 4, 9, 11}
list(f)
# >>> [11, 9, 3, 4]

如果您想知道这个用例:正如我所说的,我天真地认为在将集合转换为列表时,排序将保持不变,而实际上并非如此。错误的排序导致在运行代码时出错。幸运的是,使用sorted(set)而不是list(set)很容易修复,但首先要找出错误需要一些时间

因此,对于这个问题,我试图理解正在发生的事情,而不是寻找解决方案


Tags: orofthe项目add列表for排序
1条回答
网友
1楼 · 发布于 2024-04-19 08:45:06

我在Python上3.7.4.,我所有的list(set)顺序都与repr(set)顺序一致。下面是对10000个样本的快速测试(code)

import random
import pandas as pd

# create a function to generate random set of 0-999 with len of 3 - 20
f = lambda: set(random.randrange(1000) for i in range(random.randrange(3, 21)))

# create a DataFrame of 10000 rows with random sets
df = pd.DataFrame({'sets': [f() for i in range(10000)]})

# Create a column of repr(set) and retrieve the order in str
df['reprs'] = df['sets'].apply(repr).str.strip('{}')

# Create a column of list(set) and retrieve the order in str
df['lists'] = df['sets'].apply(list).astype(str).str.strip('[]')

# Create a comparison column
df['match'] = df['reprs'].eq(df['lists'])

# Take a look of the reprs and lists...
print(df[['reprs', 'lists']])

# Summarize
summary = df.groupby('match')['sets'].count()
print(summary)

结果:

match
True    10000
Name: sets, dtype: int64

所以我想,如果您想关注set是如何表示的,这是每个初始注释的实现细节

相关问题 更多 >