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

Python 将集合转换为列表时,什么决定了项目顺序?,python,python-3.x,list,sorting,set,Python,Python 3.x,List,Sorting,Set,我知道有几个类似的问题,但我还没有找到一个能说明我想知道什么的问题。如果这是重复的,请指出 因此我知道Python中的set是一个无序的集合,而list可以排序。我想知道的是,当列表从集合转换时,是什么决定了列表项的顺序 即使一个集合“技术上”没有排序(我猜这只是意味着你不能像处理序列类型那样与它交互),但在打印集合时,仍然存在一种顺序,例如,必须先打印一个项目、第二个项目、第三个项目等等。这种逻辑需要存在。但它甚至更进一步。例如,如果您声明两个处于“加扰”状态的集合,其中包含可排序的项,那么在

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

因此我知道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}
此外,当您
向集合中添加新项目并打印集合时,新项目会显示在正确的位置,即集合排序后的位置:

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]
list(d)  
# >>> [3, 11, 4]
print(d)
# >>> {3, 11, 4}
确定列表顺序和调用
print(set)
的逻辑似乎是相同的:

# 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]
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)
很容易修复,但首先要找出错误需要一些时间


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

我使用的是Python
3.7.4。
并且我所有的
list(set)
顺序都与
repr(set)
顺序一致。下面是对10000个样本的快速测试:

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)
结果:


因此,我可以想象,如果您想关注
set
是如何表示的,这是每个初始注释的一个实现细节。

这可能是一个实现细节。您是否特别询问了CPython,该实现可在上获得?很有趣!我正在使用Anaconda构建版本3.18.11和Python 3.7.7。如果这就是你要问的?我使用的是香草
3.7.4
,我的
repr(some\u set)
总是与
列表(some\u set)
的顺序相同。我无法重现上一个示例中的情况,其中
repr(f)
list(f)
不同。联合集也是如此。请注意,
repr({3,11,4})
repr({11,3,4})
不同。感谢您的关注!那么,这是否意味着对于不同的Python环境,您实际应用了不同类型的逻辑?为什么会这样?我的意思是,为什么需要更改这些东西呢?实现细节的更改可以在版本之间发生,无论是有意的还是无意的,对于各种不同风格的Python也是如此。例如,
dict
在作为实现细节的
3.6
之前一直是无序的,只是在
3.7
中才正式成为插入顺序。我不太精通低级,无法理解这些细节,但如果您感兴趣,请查看。