0

Given this python code snippet:

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))

The purpose of this code is to perform a random extraction of 2 elements from a set. The problem is that the np.random.choiche function does not accept a set, so you have to turn it into a list. But, doing this, the order of the elements is random and given the same seed, the result of the random extraction is not replicable. In this case I implemented a function that sorts the elements, but it is costly.

You will rightly say, use a list instead of a set. To this I reply that sets fit perfectly the use I need. For example, this structure allows the Agent.friends attribute to have no duplicate elements.

So, my question is, what is the most convenient method, other than the function I implemented, to use sets and have the random extraction from a set be deterministic? Is it better to use lists instead of sets? Is there any way to make the transformation deterministic?

Thanks in advance.

EDIT: Some observe that internally the transformation from set to list is consistent. My objective is for this transformation to be consistent externally as well. So that by running the same script numerous times, the extraction of the default_rng instance is the same.

  • *so you have to turn it into a list. But, doing this, the order of the elements is random*. Do you have an example? In all my tests, the order of the elements in a set is *internaly* consistant. Whatever the order the same elements are added to the set, they are always iterated in the same order. That order is not specified, but it is consistant. – Serge Ballesta Feb 26 '21 at 12:26
  • If I get your point: Internally it is consistent. but I would like it to be consistent externally as well. In short: By launching the same script multiple times, I want the same extraction from the default_rng instance. – Francesco Mattioli Feb 26 '21 at 12:36
  • by the way, thanks for the observation. – Francesco Mattioli Feb 26 '21 at 12:36
  • If you launch the script multiple times, you should get the same (apparently random) order. – Serge Ballesta Feb 26 '21 at 13:04
  • This doesn't happen! Or at least, this doesn't happen in Python 3.8 – Francesco Mattioli Feb 26 '21 at 13:16
  • No, I was wrong, you're right! But at this point I think there's a problem with pycharm. Because if I run this script multiple times using pycharm, I get different results. But, if I use this command (for ($i=1; $i -le 10; $i++) { python script.py } ) from a powershell, I always get the same result. (Same conda env) – Francesco Mattioli Feb 26 '21 at 13:31

2 Answers2

0

You can use ordered set.

From the documentation:

from ordered_set import OrderedSet

>>>OrderedSet('abracadabra')
OrderedSet(['a', 'b', 'r', 'c', 'd'])
Husseinfo
  • 472
  • 2
  • 9
0

Solved by overriding the hash() method. Source: 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))