英文:
How to efficiently generate unique random non-zero integers from specific spaces in a range?
问题
以下是您要翻译的代码部分:
import random
my_list = []
c = 0
while c < 100:
if c < 5:
# Both values are unique.
first_num, second_num = random.sample(range(-5, 6), 2)
# Exclusion of 0.
while first_num == 0 or second_num == 0:
first_num, second_num = random.sample(range(-5, 6), 2)
c += 1
elif 5 <= c < 80:
first_num, second_num = random.sample(range(-100, 101), 2)
while first_num == 0 or second_num == 0:
first_num, second_num = random.sample(range(-100, 101), 2)
c += 1
else:
first_num, second_num = random.sample(range(-150, 151), 2)
while first_num == 0 or second_num == 0:
first_num, second_num = random.sample(range(-150, 151), 2)
c += 1
random_nums = (first_num, second_num)
if random_nums not in my_list:
my_list.append(random_nums)
else:
c -= 1
如果您有任何其他需要翻译的内容,请随时提出。
英文:
I want to generate 100 pairs of unique random non-zero integers from the range (-150, 151). But I want my code to generate from specific areas in (-150, 151). I have coded it as follows:
import random
my_list = []
c = 0
while c < 100:
if c < 5:
# Both values are unique.
first_num, second_num = random.sample(range(-5, 6), 2)
# Exclusion of 0.
while first_num == 0 or second_num == 0:
first_num, second_num = random.sample(range(-5, 6), 2)
c += 1
elif 5 <= c < 80:
first_num, second_num = random.sample(range(-100, 101), 2)
while first_num == 0 or second_num == 0:
first_num, second_num = random.sample(range(-100, 101), 2)
c += 1
else:
first_num, second_num = random.sample(range(-150, 151), 2)
while first_num == 0 or second_num == 0:
first_num, second_num = random.sample(range(-150, 151), 2)
c += 1
random_nums = (first_num, second_num)
if random_nums not in my_list:
my_list.append(random_nums)
else:
c -= 1
Is there a more elegant or efficient way alternative to what I have coded above?
UPDATE
After discussing with MatBailie in the comments, I am updating the requirements:
If the whole selected range is (-150 to 151), then in the final my_list
:
- (5,6), (6,5) are allowed but (5,6), (5,6) are not.
- If (-1, 1) is generated once from range (-5 to 6) then it should not be generated again from the bigger ranges such as (-100 to 101) or (-150 to 151)
- It is also good to have pairs such as (-1, 140) or (140, -1).
UPDATE
Benchmarking MatBailie, Alain T. and Samwise's answers on perfpy with 100 pairs, I got the following result:
The same benchmark with generating 1000 pairs and the same ratio of areas, I got this:
答案1
得分: 2
以下是代码的中文翻译:
# 可以构建一个包含100个范围的列表,以满足所需大小的分组。这将使剩下的逻辑更加通用和简单:
import random
ranges = [range(-5,6)]*5 + [range(-100,101)]*75 + [range(-150,151)]*20
pairs = []
for R in ranges:
a = 0
while not a or not b or (a,b) in pairs:
a,b = random.sample(R,2) # random.choices(R,k=2)
pairs.append((a,b))
# 输出:
print(pairs)
# [(-3, 2), (-3, -5), (3, 1), (-4, -3), (2, 4), (-73, -9), (16, -56),
# (12, -81), (5, -50), (99, -6), (35, 71), (30, -75), (98, 25), (55, -58),
# (73, -24), (-65, 4), (75, -96), (-6, -90), (-80, 22), (-93, -39),
# (-69, -48), (-30, 25), (85, -11), (37, 60), (91, 96), (98, 100),
# (-100, -54), (58, 20), (-14, -95), (-76, -12), (-5, -84), (70, -53),
# (91, -66), (-61, 2), (4, -42), (-15, -70), (-52, -6), (-5, 93), (26, 76),
# (-8, -79), (63, -7), (-23, -27), (56, 13), (46, 27), (80, 94), (-94, -66),
# (-46, -19), (-4, -87), (-92, -48), (24, 32), (10, -89), (-50, -96),
# (-5, -85), (-32, 69), (-60, 69), (87, -81), (-100, -91), (87, 37),
# (-60, 45), (-70, -84), (-98, 80), (-88, 57), (-67, -44), (-72, 4),
# (-76, 5), (-79, -16), (-9, 80), (76, -41), (15, 77), (-47, -1), (58, 12),
# (66, -2), (21, 16), (-24, -12), (54, -69), (58, -73), (61, 68), (-89, -37),
# (-85, 68), (-7, -21), (-86, -31), (48, 136), (137, 86), (-61, -32),
# (104, -144), (-24, -103), (80, 135), (-2, 39), (49, -21), (15, -103),
# (-14, -145), (-48, -61), (142, -90), (93, -132), (-68, -111), (-80, 2),
# (6, 45), (-89, 75), (-146, -76), (-94, -24)]
# 你也可以只使用一个列表来实现,通过初始化包含范围的结果列表,然后用生成的对替换范围:
pairs = [range(-5,6)]*5 + [range(-100,101)]*75 + [range(-150,151)]*20
for i,R in enumerate(pairs):
pairs[i] = (0,0)
while not all(pairs[i]) or pairs.index(pairs[i])<i:
pairs[i] = random.sample(R,2) # random.choices(R,k=2)
注意:请确保在代码中不要使用HTML实体"lt",而应使用小于号"<"。
英文:
You could build a list of the 100 ranges repeating the same ones in groups of the required size. This will make the rest of the logic more generalized and simpler:
import random
ranges = [range(-5,6)]*5 + [range(-100,101)]*75 + [range(-150,151)]*20
pairs = []
for R in ranges:
a = 0
while not a or not b or (a,b) in pairs:
a,b = random.sample(R,2) # random.choices(R,k=2)
pairs.append((a,b))
output:
print(pairs)
[(-3, 2), (-3, -5), (3, 1), (-4, -3), (2, 4), (-73, -9), (16, -56),
(12, -81), (5, -50), (99, -6), (35, 71), (30, -75), (98, 25), (55, -58),
(73, -24), (-65, 4), (75, -96), (-6, -90), (-80, 22), (-93, -39),
(-69, -48), (-30, 25), (85, -11), (37, 60), (91, 96), (98, 100),
(-100, -54), (58, 20), (-14, -95), (-76, -12), (-5, -84), (70, -53),
(91, -66), (-61, 2), (4, -42), (-15, -70), (-52, -6), (-5, 93), (26, 76),
(-8, -79), (63, -7), (-23, -27), (56, 13), (46, 27), (80, 94), (-94, -66),
(-46, -19), (-4, -87), (-92, -48), (24, 32), (10, -89), (-50, -96),
(-5, -85), (-32, 69), (-60, 69), (87, -81), (-100, -91), (87, 37),
(-60, 45), (-70, -84), (-98, 80), (-88, 57), (-67, -44), (-72, 4),
(-76, 5), (-79, -16), (-9, 80), (76, -41), (15, 77), (-47, -1), (58, 12),
(66, -2), (21, 16), (-24, -12), (54, -69), (58, -73), (61, 68), (-89, -37),
(-85, 68), (-7, -21), (-86, -31), (48, 136), (137, 86), (-61, -32),
(104, -144), (-24, -103), (80, 135), (-2, 39), (49, -21), (15, -103),
(-14, -145), (-48, -61), (142, -90), (93, -132), (-68, -111), (-80, 2),
(6, 45), (-89, 75), (-146, -76), (-94, -24)]
You could also do this using only one list by initializing the resulting list with ranges that you replace with the generated pairs:
pairs = [range(-5,6)]*5 + [range(-100,101)]*75 + [range(-150,151)]*20
for i,R in enumerate(pairs):
pairs[i] = (0,0)
while not all(pairs[i]) or pairs.index(pairs[i])<i:
pairs[i] = random.sample(R,2) # random.choices(R,k=2)
答案2
得分: 2
这是你要翻译的内容:
"已经过了午夜,但我将尽力解释...
基本原则是我要计算在给定范围内(不包括零)有多少不同的配对,然后在该范围上运行一个样本,以确保没有重复项。
然后,我编写一个函数来“解码”这些整数为配对。
所以,如果我想要一个元素在范围-4到+4之间的配对,不包括零,不包括范围-2到+2的配对,我可以将其映射到可能配对的网格...
-4 -3 -2 -1 +0 +1 +2 +3 +4
+4 O O O O X O O O O
+3 O O O O X O O O O
+2 O O X X X X X O O
+1 O O X X X X X O O
+0 X X X X X X X X X
-1 O O X X X X X O O
-2 O O X X X X X O O
-3 O O O O X O O O O
-4 O O O O X O O O O
O = 可能的配对
X = 排除的配对
有48种允许的可能配对。
- 48 = (4² - 2²) * 4
然后,我编写一个函数,可以将值0..47中的每个值转换为这些允许的可能配对之一。
import random
from pprint import pprint
def decode(val, lower, upper):
q = val % 4
v = val >> 2
x = v % (upper + lower) - lower
if x >= 0:
x += 1
y = v // (upper + lower) + lower + 1
if q in (1,3):
x = -x
y = -y
if q in (2,3):
x,y = -y,x
return (x,y)
def pairs(n, lower, upper):
return [
decode(id, lower, upper)
for id in random.sample(
range((upper**2 - lower**2) * 4),
n
)
]
# 较小的范围用于使其可打印和可测试
result = [
*pairs( 5, 0, 5), # 在范围-5到5的情况下有5对,不包括范围-0到0的情况
*pairs( 5, 5, 10), # 在范围-10到10的情况下有5对,不包括范围-5到5的情况
*pairs( 5, 10, 20) # 在范围-20到20的情况下有5对,不包括范围-10到10的情况
]
pprint(result)
演示:https://trinket.io/python3/f9e65fe9ef"
英文:
It's gone past midnight, but I'll do my best to explain...
The basic principle is that I work out how many different pairs there are in a given range (excluding any zeros), and run a sample on that range, so I know there are no duplicates.
Then I code a function to "decode" those integers in to a pairs.
So, if I want a pair with elements in the range -4 to +4, excluding zeros, excluding pairs from the range -2 to +2, I can map that to a grid of possible pairs...
-4 -3 -2 -1 +0 +1 +2 +3 +4
+4 O O O O X O O O O
+3 O O O O X O O O O
+2 O O X X X X X O O
+1 O O X X X X X O O
+0 X X X X X X X X X
-1 O O X X X X X O O
-2 O O X X X X X O O
-3 O O O O X O O O O
-4 O O O O X O O O O
O = Possible pair
X = Excluded pair
There are 48 allowed possible pairs.
- 48 = (4² - 2²) * 4
I then write a function that can turn each of the values 0..47 in to a different one of those allowed possible pairs.
import random
from pprint import pprint
def decode(val, lower, upper):
q = val % 4
v = val >> 2
x = v % (upper + lower) - lower
if x >= 0:
x += 1
y = v // (upper + lower) + lower + 1
if q in (1,3):
x = -x
y = -y
if q in (2,3):
x,y = -y,x
return (x,y)
def pairs(n, lower, upper):
return [
decode(id, lower, upper)
for id in random.sample(
range((upper**2 - lower**2) * 4),
n
)
]
# smaller ranges used to make it printable and testable
result = [
*pairs( 5, 0, 5), # 5 pairs with values in the range - 5 to 5, except pairs using the range - 0 to 0
*pairs( 5, 5, 10), # 5 pairs with values in the range -10 to 10, except pairs using the range - 5 to 5
*pairs( 5, 10, 20) # 5 pairs with values in the range -20 to 20, except pairs using the range -10 to 10
]
pprint(result)
答案3
得分: 1
以下是您要翻译的内容:
我可以这样做,使用一个数字列表来获取“sample”,而不必多余地删除零,使用一个字典来强制唯一性(使用集合会更简单,但字典会保留插入顺序,如果您希望最终列表中的不同样本的排列方式相同,并且较小的数字位于前面,这很重要):
```python
import random
max_num = 150
nums = list(range(-max_num, max_num))
nums.remove(0)
my_list = list({
tuple(
random.sample(nums[max_num-r:r-max_num or None], 2)
): 0
for c, r in ((5, 5), (75, 100), (20, 150))
for _ in range(c)
})
生成一个单独的nums
列表比为每个样本群体生成一个新列表稍微复杂一些,但效率更高,因为我们不需要反复重新分配它,只需根据需要取片段。
请注意,max_num
需要至少与for c, r
迭代中所有r
值一样大,否则我们将无法通过使用max_num-r
等来切片nums
来获得所需的范围。
<details>
<summary>英文:</summary>
I might do it like this, using a list of numbers to be able to take the `sample` without having to take an extra step of dropping the zeroes, and using a dict to enforce uniqueness (a set would be simpler, but a dict preserves insertion order, which is important if you want the same arrangement of the different samples in the final list, with smaller numbers toward the beginning):
import random
max_num = 150
nums = list(range(-max_num, max_num))
nums.remove(0)
my_list = list({
tuple(
random.sample(nums[max_num-r:r-max_num or None], 2)
): 0
for c, r in ((5, 5), (75, 100), (20, 150))
for _ in range(c)
})
Generating a single `nums` list is a little more complicated than generating a new list for each sample population, but is more efficient since then we don't need to repeatedly re-allocate it, and can simply take slices as needed.
Note that `max_num` needs to be at least as big as all of the `r` values in the `for c, r` iteration, or we won't be able to get the desired range by slicing `nums` with `max_num-r` etc.
</details>
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论