避免随机变量的对象重复实例

huangapple go评论97阅读模式
英文:

avoiding duplicate instances of an object with random variables

问题

我一直在努力寻找一个足够简单的解决方案来解决以下问题

假设我有一个类其中定义了两个变量如下所示在x-y网格上的点):
```python
class Target:
    def __init__(self):
        self.x = random.randint(1, 9)
        self.y = random.randint(1, 9)

我需要生成一定数量的这些对象,比如说10个:

for i in range(10):
    t = Target()

当然,有时坐标会重叠。

如何确保没有任何对象具有相同的x和y变量,这将是最简单的方法?我尝试过一些解决方案,但它们感觉过于复杂,我觉得应该有一个相对简单的方法。


<details>
<summary>英文:</summary>

I&#39;ve been struggling to find a simple enough solution to the following problem:

Let&#39;s say I have a class with two variables defined, like below (points on a x-y grid):  
```python
class Target:
    def __init__(self):  
        self.x = random.randint(1, 9)  
        self.y = random.randint(1, 9)  

I need to generate a given amount of those, let's say 10:

for i in range(10):  
    t = Target()  

Of course, sometimes the coordinates overlap.

What would be the simplest way to assure none of the objects have the same x and y variables? I've been trying some solutions, but they feel overwrought and I feel there must be a relatively simple one.

答案1

得分: 2

首先,调整你的类以将 xy 坐标作为初始化参数。

class Target:
    def __init__(self, x, y):  
        self.x = x
        self.y = y 

然后,你可以生成一个包含所有有效坐标对的列表。

xy = [(x, y) for x in range(1, 10) for y in range(1, 10)]

然后,无重复地随机抽取大小为 10 的样本。

xy_sample = random.sample(xy, 10)

然后初始化 10 个类的实例。

targets = [Target(x, y) for x, y in xy_sample]

注意:如果坐标空间非常庞大,那么仅在集合中跟踪生成的 xy 对,以及在极少情况下命中重复时重新生成随机数可能更加可行。

英文:

First, adjust your class to take the x and y coordinates as initialization parameters.

class Target:
    def __init__(self, x, y):  
        self.x = x
        self.y = y 

Then you could generate a list of all valid coordinate pairs.

xy = [(x, y) for x in range(1, 10) for y in range(1, 10)]

Then take a random sample of size 10 without replacement.

xy_sample = random.sample(xy, 10)

Then initialize 10 instances of your class.

targets = [Target(x, y) for x, y in xy_sample]

Caveat: if the xy-space is huge then just keeping track of the generated x, y pairs in a set and rerolling the randomly generated numbers in the unlikely case that you hit a duplicate may be more feasible.

答案2

得分: 2

假设您的类构造函数的接口已设置,而且您无法更改它(或者不想更改它),所以随机化部分需要放在__init__方法内。并且假设您主要希望"确保"在Target对象列表中没有重复项,而不对您确切要实现的目标做任何进一步的假设。

首先,您需要使Target对象之间可比较,基于它们的xy值。这可以在__eq__方法中实现:

def __eq__(self, other):
     return self.x == other.x and self.y == other.y

此外,您需要创建__hash__方法,这是要求对于基于__eq__相等的对象必须相等的,因为重新实现__eq__会重置默认的__hash__,所以Target对象没有哈希值,您可以这样实现:

def __hash__(self):
     return hash((self.x, self.y))  # 只需使用元组的哈希值

现在,您可以基于它们的(x,y)数据来比较Target对象:

Target() == Target()

这在以前也可以工作,但会返回这两个目标对象是否相同,即使它们具有相同的x和y值也可能返回False

基于这个基础,您现在可以断言您的目标对象列表中没有重复项:

targets = [Target() for in range(10)]

通过将其转换为一个set,这将基于__eq__的相等性来删除重复项,然后比较结果的长度:

assert len(targets) == len(set(targets))

这可能不是做的最有意义的事情,但它是对您问题的直接答案。

英文:

Assuming your class constructor's interface is set and you can't change it (or don't want to), so the randomization part needs to be inside __init__. And also assuming that just "assuring" there are no dupes in a list of Targets is primarily what you want, without any further assumptions made on what you're exactly trying to achieve.

Then, as a first step, you would require for the Targets to be comparable to each other, based on their x and y values.This can be implemented in the __eq__ method:

def __eq__(self, other):
     return self.x == other.x and self.y == other.y

Alongside, you need to create __hash__, which is required to be equal for objects that are equal based on __eq__, and also because reimplementing __eq__ resets the default __hash__ so Target wouldn't be hashable without:

def __hash__(self):
     return hash((self.x, self.y))  # just use the tuple&#39;s hash

Now you can compare Targets with one another based on their (x,y) data:

Target() == Target()

This worked before, too, but would return if the two targets are the same object, which may be False even with the same x and y.

With this as the basis, you can now assert there are no dupes in your list of targets

targets = [Target() for in range(10)]

by turning it into a set, which removes dupes based on equality based on __eq__, and then comparing the length of the result:

assert len(targets) == len(set(targets))

This is may not be what makes the most sense to do, but a direct answer to your question nonetheless.

答案3

得分: 1

这使用一个记住旧选择的生成器。
小心:如果创建的Target类的数量超过可用组合,该函数可能会变成无限循环...

import numpy as np

class CustomGenerator(object):
    def __init__(self, lower_bound: int, upper_bound: int):
        self.old_values = []
        self.lower_bound = lower_bound
        self.upper_bound = upper_bound

    def __iter__(self):
        return self

    def __next__(self):
        return self.next()

    def next(self):
        while True:
            new_vals = tuple(np.random.randint(self.lower_bound, self.upper_bound, 2))
            if new_vals not in self.old_values:
                break
        return new_vals

gen = CustomGenerator(0, 100)

class Target:
    def __init__(self, gen):  
        self.x, self.y = next(gen)

    def __repr__(self) -> str:
        return f"{self.x}, {self.y}"

t = Target(gen)
print(t)
英文:

This uses a generator that remebers the old choices.
Carefull: The function can turn into an infinity loop if you create more classes of Target than there are available combinations...

import numpy as np

class CustomGenerator(object):
    def __init__(self, lower_bound: int, upper_bound: int):
        self.old_values = []
        self.lower_bound = lower_bound
        self.upper_bound = upper_bound

    def __iter__(self):
        return self

    def __next__(self):
        return self.next()

    def next(self):
        while True:
            new_vals = tuple(np.random.randint(self.lower_bound, self.upper_bound, 2))
            if new_vals not in self.old_values:
                break
        return new_vals

gen = CustomGenerator(0, 100)

class Target:
    def __init__(self, gen):  
        self.x, self.y = next(gen)

    def __repr__(self) -&gt; str:
        return f&quot;{self.x}, {self.y}&quot;

t = Target(gen)
print(t)

huangapple
  • 本文由 发表于 2023年3月9日 18:07:50
  • 转载请务必保留本文链接:https://go.coder-hub.com/75683100.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定