如何 return 考虑互斥项的随机列表?
How to return a shuffled list considering mutually exclusive items?
假设我有一个选项列表,我想随机选择一个数字。
在我的例子中,假设选项在列表 ['a', 'b', 'c', 'd', 'e']
中,我希望我的脚本包含 return 3 个元素。
不过也有两个选项不能同时出现的情况。也就是说,如果选项 'a' 是随机选择的,则选项 'b' 不能被选择。反之亦然。
所以有效的输出是:['a', 'c', 'd']
或 ['c', 'd', 'b']
,而像 ['a', 'b', 'c']
这样的东西不会,因为它们同时包含 'a' 和 'b'.
为了满足这些要求,我正在获取 3 个选项和另一个选项以补偿可能的丢弃。然后,我保留一个具有互斥条件的 set()
并继续从中删除并检查是否已选择两个元素:
import random
mutually_exclusive = set({'a', 'b'})
options = ['a', 'b', 'c', 'd', 'e']
num_options_to_return = 3
shuffled_options = random.sample(options, num_options_to_return + 1)
elements_returned = 0
for item in shuffled_options:
if elements_returned >= num_options_to_return:
break
if item in mutually_exclusive:
mutually_exclusive.remove(item)
if not mutually_exclusive:
# if both elements have appeared, then the set is empty so we cannot return the current value
continue
print(item)
elements_returned += 1
但是,我可能编码过多,Python 可能有更好的方法来处理这些要求。通过 random
's documentation 我无法找到开箱即用的方法。有没有比我现在的解决方案更好的解决方案?
一种方法是使用 itertools.combinations
to create all of the possible results, filter out the invalid ones and make a random.choice
来自于:
>>> from itertools import combinations
>>> from random import choice
>>> def is_valid(t):
... return 'a' not in t or 'b' not in t
...
>>> choice([
... t
... for t in combinations('abcde', 3)
... if is_valid(t)
... ])
...
('c', 'd', 'e')
可能有点幼稚,但您可以生成样本直到满足您的条件:
import random
options = ['a', 'b', 'c', 'd', 'e']
num_options_to_return = 3
mutually_exclusive = set({'a', 'b'})
while True:
shuffled_options = random.sample(options, num_options_to_return)
if all (item not in mutually_exclusive for item in shuffled_options):
break
print(shuffled_options)
我会用集合来实现它:
import random
mutually_exclusive = {'a', 'b'}
options = ['a', 'b', 'c', 'd', 'e']
num_options_to_return = 3
while True:
s = random.sample(options, num_options_to_return)
print('Sample is', s)
if not mutually_exclusive.issubset(s):
break
print('Discard!')
print('Final sample:', s)
打印(例如):
Sample is ['a', 'b', 'd']
Discard!
Sample is ['b', 'a', 'd']
Discard!
Sample is ['e', 'a', 'c']
Final sample: ['e', 'a', 'c']
您可以重组您的选择。
import random
options = [('a', 'b'), 'c', 'd', 'e']
n_options = 3
selected_option = random.sample(options, n_options)
result = [item if not isinstance(item, tuple) else random.choice(item)
for item in selected_option]
print(result)
我创建了以下函数,我认为它也值得分享 ;-)
def random_picker(options, n, mutually_exclusives=None):
if mutually_exclusives is None:
return random.sample(options, n)
elif any(len(pair) != 2 for pair in mutually_exclusives):
raise ValueError('Lenght of pairs of mutually_exclusives iterable, must be 2')
res = []
while len(res) < n:
item_index = random.randint(0, len(options) - 1)
item = options[item_index]
if any(item == exc and pair[-(i - 1)] in res for pair in mutually_exclusives
for i, exc in enumerate(pair)):
continue
res.append(options.pop(item_index))
return res
其中:
options
是可供选择的可用选项列表。
n
是您要从 options
中挑选的项目数
mutually_exclusives
是一个包含互斥项 的元组对的可迭代对象
您可以按如下方式使用:
>>> random_picker(['a', 'b', 'c', 'd', 'e'], 3)
['c', 'e', 'a']
>>> random_picker(['a', 'b', 'c', 'd', 'e'], 3, [('a', 'b')])
['d', 'b', 'e']
>>> random_picker(['a', 'b', 'c', 'd', 'e'], 3, [('a', 'b'), ('a', 'c')])
['e', 'd', 'a']
import random
l = [['a','b'], ['c'], ['d'], ['e']]
x = [random.choice(i) for i in random.sample(l,3)]
这里l
是一个二维列表,第一层反映and
关系,第二层反映or
关系。
假设我有一个选项列表,我想随机选择一个数字。
在我的例子中,假设选项在列表 ['a', 'b', 'c', 'd', 'e']
中,我希望我的脚本包含 return 3 个元素。
不过也有两个选项不能同时出现的情况。也就是说,如果选项 'a' 是随机选择的,则选项 'b' 不能被选择。反之亦然。
所以有效的输出是:['a', 'c', 'd']
或 ['c', 'd', 'b']
,而像 这样的东西不会,因为它们同时包含 'a' 和 'b'.['a', 'b', 'c']
为了满足这些要求,我正在获取 3 个选项和另一个选项以补偿可能的丢弃。然后,我保留一个具有互斥条件的 set()
并继续从中删除并检查是否已选择两个元素:
import random
mutually_exclusive = set({'a', 'b'})
options = ['a', 'b', 'c', 'd', 'e']
num_options_to_return = 3
shuffled_options = random.sample(options, num_options_to_return + 1)
elements_returned = 0
for item in shuffled_options:
if elements_returned >= num_options_to_return:
break
if item in mutually_exclusive:
mutually_exclusive.remove(item)
if not mutually_exclusive:
# if both elements have appeared, then the set is empty so we cannot return the current value
continue
print(item)
elements_returned += 1
但是,我可能编码过多,Python 可能有更好的方法来处理这些要求。通过 random
's documentation 我无法找到开箱即用的方法。有没有比我现在的解决方案更好的解决方案?
一种方法是使用 itertools.combinations
to create all of the possible results, filter out the invalid ones and make a random.choice
来自于:
>>> from itertools import combinations
>>> from random import choice
>>> def is_valid(t):
... return 'a' not in t or 'b' not in t
...
>>> choice([
... t
... for t in combinations('abcde', 3)
... if is_valid(t)
... ])
...
('c', 'd', 'e')
可能有点幼稚,但您可以生成样本直到满足您的条件:
import random
options = ['a', 'b', 'c', 'd', 'e']
num_options_to_return = 3
mutually_exclusive = set({'a', 'b'})
while True:
shuffled_options = random.sample(options, num_options_to_return)
if all (item not in mutually_exclusive for item in shuffled_options):
break
print(shuffled_options)
我会用集合来实现它:
import random
mutually_exclusive = {'a', 'b'}
options = ['a', 'b', 'c', 'd', 'e']
num_options_to_return = 3
while True:
s = random.sample(options, num_options_to_return)
print('Sample is', s)
if not mutually_exclusive.issubset(s):
break
print('Discard!')
print('Final sample:', s)
打印(例如):
Sample is ['a', 'b', 'd']
Discard!
Sample is ['b', 'a', 'd']
Discard!
Sample is ['e', 'a', 'c']
Final sample: ['e', 'a', 'c']
您可以重组您的选择。
import random
options = [('a', 'b'), 'c', 'd', 'e']
n_options = 3
selected_option = random.sample(options, n_options)
result = [item if not isinstance(item, tuple) else random.choice(item)
for item in selected_option]
print(result)
我创建了以下函数,我认为它也值得分享 ;-)
def random_picker(options, n, mutually_exclusives=None):
if mutually_exclusives is None:
return random.sample(options, n)
elif any(len(pair) != 2 for pair in mutually_exclusives):
raise ValueError('Lenght of pairs of mutually_exclusives iterable, must be 2')
res = []
while len(res) < n:
item_index = random.randint(0, len(options) - 1)
item = options[item_index]
if any(item == exc and pair[-(i - 1)] in res for pair in mutually_exclusives
for i, exc in enumerate(pair)):
continue
res.append(options.pop(item_index))
return res
其中:
options
是可供选择的可用选项列表。n
是您要从options
中挑选的项目数
mutually_exclusives
是一个包含互斥项 的元组对的可迭代对象
您可以按如下方式使用:
>>> random_picker(['a', 'b', 'c', 'd', 'e'], 3)
['c', 'e', 'a']
>>> random_picker(['a', 'b', 'c', 'd', 'e'], 3, [('a', 'b')])
['d', 'b', 'e']
>>> random_picker(['a', 'b', 'c', 'd', 'e'], 3, [('a', 'b'), ('a', 'c')])
['e', 'd', 'a']
import random
l = [['a','b'], ['c'], ['d'], ['e']]
x = [random.choice(i) for i in random.sample(l,3)]
这里l
是一个二维列表,第一层反映and
关系,第二层反映or
关系。