【问题标题】:Python, Casting a list from a set changes the order. What is the best way to avoid this?Python,从集合中转换列表会更改顺序。避免这种情况的最佳方法是什么?
【发布时间】:2021-02-26 12:09:17
【问题描述】:

给定这个python代码sn-p:

import numpy as np
rng = np.random.default_rng(42)

class Agent:
    def __init__(self, id):
        self.id = id
        self.friends = set()

    def __repr__(self):
        return str(self.id)

group_list = list()
for i in range(100):
    new_obj = Agent(i)
    group_list.append(new_obj)

for person in group_list:
    pool = rng.choice([p for p in group_list if p != person], 6)
    for p in pool:
        person.friends.add(p)

def set_to_list_ordered(a_set):
    return sorted(list(a_set), key=lambda x: x.id)

print("This will change: ")
print(rng.choice(list(group_list[0].friends), 2))
print("This will not change: ")
print(rng.choice(set_to_list_ordered(group_list[0].friends), 2))

此代码的目的是从集合中随机抽取 2 个元素。问题是 np.random.choiche 函数不接受集合,所以你必须把它变成一个列表。但是,这样做,元素的顺序是随机的,并且给定相同的种子,随机提取的结果是不可复制的。在这种情况下,我实现了一个对元素进行排序的函数,但它的成本很高。

您会说得对,使用列表而不是集合。对此,我回答说套装完全适合我需要的用途。例如,这种结构允许 Agent.friends 属性没有重复元素。

所以,我的问题是,除了我实现的函数之外,最方便的方法是使用集合并从集合中随机提取是确定性的?使用列表而不是集合更好吗?有没有办法使转换具有确定性?

提前致谢。

编辑: 一些人观察到,从集合到列表的转换在内部是一致的。我的目标是让这种转变在外部也保持一致。这样通过多次运行相同的脚本,default_rng实例的提取是相同的。

【问题讨论】:

  • 所以你必须把它变成一个列表。但是,这样做,元素的顺序是随机的。你有一个例子吗?在我所有的测试中,集合中元素的顺序是internaly 一致的。无论将相同元素添加到集合中的顺序如何,它们总是以相同的顺序迭代。该顺序没有指定,但它是一致的。
  • 如果我明白你的意思:内部是一致的。但我希望它在外部也保持一致。简而言之:通过多次启动同一个脚本,我希望从 default_rng 实例中提取相同的内容。
  • 顺便说一句,感谢您的观察。
  • 如果你多次启动脚本,你应该得到相同的(显然是随机的)顺序。
  • 这不会发生!或者至少,这在 Python 3.8 中不会发生

标签: python python-3.x pep


【解决方案1】:

您可以使用ordered set

来自文档:

from ordered_set import OrderedSet

>>>OrderedSet('abracadabra')
OrderedSet(['a', 'b', 'r', 'c', 'd'])

【讨论】:

  • 我看过这个包,但我不想在我的项目中添加依赖项。
【解决方案2】:

通过覆盖 hash() 方法解决。来源:https://www.youtube.com/watch?v=C4Kc8xzcA68

import numpy as np
rng = np.random.default_rng(42)

class Agent:
    def __init__(self, id):
        self.id = id
        self.friends = set()

    def __repr__(self):
        return str(self.id)
   
    def __hash__(self):
        return self.id


group_list = list()
for i in range(100):
    new_obj = Agent(i)
    group_list.append(new_obj)

for person in group_list:
    pool = rng.choice([p for p in group_list if p != person], 6)
    for p in pool:
        person.friends.add(p)

def set_to_list_ordered(a_set):
    return sorted(list(a_set), key=lambda x: x.id)

print("This will change: ")
print(rng.choice(list(group_list[0].friends), 2))
print("This will not change: ")
print(rng.choice(set_to_list_ordered(group_list[0].friends), 2))

【讨论】:

    猜你喜欢
    • 2019-10-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-08-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多