繁体   English   中英

如何确保列表中相邻的两个数字不同

[英]how to make sure that two numbers next to each other in a list are different

我有一个生成随机数列表的简单代码。

x = [random.randrange(0,11) for i in range(10)]

我遇到的问题是,由于它是随机的,它有时会产生彼此相邻的重复数字。 我如何更改代码以使其永远不会发生? 我正在寻找这样的东西:

[1, 7, 2, 8, 7, 2, 8, 2, 6, 5]

这样每次我运行代码时,所有相邻的数字都是不同的。

x = []

while len(x) < 10:
    r = random.randrange(0,11)

    if not x or x[-1] != r:
        x.append(r)

x[-1] 包含最后插入的元素,我们检查它是否与新的随机数相同。 使用not x我们检查数组是否为空,因为它会在循环的第一次迭代期间生成IndexError

这是一种不依赖重试的方法:

>>> import random
>>> x = [random.choice(range(12))]
>>> for _ in range(9):
...     x.append(random.choice([*range(x[-1]), *range(x[-1]+1, 12)]))
...
>>> x
[6, 2, 5, 8, 1, 8, 0, 4, 6, 0]

这个想法是通过从排除先前选择的号码的列表中选择来选择每个新号码。

请注意,每次都必须重新生成一个新列表以从中选择,这实际上不能提高效率。 但是,如果您从相对较短的范围内生成一个非常长的列表,那么预先生成不同的数字池可能是值得的,这样您就可以在恒定时间内从适当的数字池中生成 select:

>>> pool = [[*range(i), *range(i+1, 3)] for i in range(3)]
>>> x = [random.choice(random.choice(pool))]
>>> for _ in range(10000):
...     x.append(random.choice(pool[x[-1]]))
...
>>> x
[0, 2, 0, 2, 0, 2, 1, 0, 1, 2, 0, 1, 2, 1, 0, ...]

O(n) 解决方案,通过从[1,stop) modulo stop随机添加到最后一个元素

import random

x = [random.randrange(0,11)]
x.extend((x[-1]+random.randrange(1,11)) % 11 for i in range(9))

x

Output

[0, 10, 4, 5, 10, 1, 4, 8, 0, 9]

Function 不迭代检查重复的解决方案,只检查每个添加列表中的最后一个数字:

import random

def get_random_list_without_neighbors(lower_limit, upper_limit, length):
    res = []
    # add the first number
    res.append(random.randrange(lower_limit, upper_limit))
    while len(res) < length:
        x = random.randrange(lower_limit, upper_limit)
        # check that the new number x doesn't match the last number in the list
        if x != res[-1]:
            res.append(x)

    return res
>>> print(get_random_list_without_neighbors(0, 11, 10)
[10, 1, 2, 3, 1, 8, 6, 5, 6, 2]
def random_sequence_without_same_neighbours(n, min, max):
    x = [random.randrange(min, max + 1)]
    uniq_value_count = max - min + 1
    next_choises_count = uniq_value_count - 1
    for i in range(n - 1):
        circular_shift = random.randrange(0, next_choises_count)
        x.append(min + (x[-1] + circular_shift + 1) % uniq_value_count)
    return x

random_sequence_without_same_neighbours(n=10, min=0, max=10)
from random import randrange
from itertools import islice, groupby

# Make an infinite amount of randrange's results available
pool = iter(lambda: randrange(0, 11), None)
# Use groupby to squash consecutive values into one and islice to at most 10 in total
result = [v for v, _ in islice(groupby(pool), 10)]

它不是很多 pythonic 但你可以做这样的事情

import random

def random_numbers_generator(n):
    "Generate a list of random numbers but without two duplicate numbers in a row "
    result = []
    for _ in range(n):
        number = random.randint(1, n)
        if result and number == result[-1]:
            continue
        result.append(number)
    return result


print(random_numbers_generator(10))

结果:

3, 6, 2, 4, 2, 6, 2, 1, 4, 7]

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM