随机为列表中的每个项目分配一个不重复的对子

问题描述 投票:4回答:5

所以我有一个列表,我想把这些值 "分配 "到一个不同的随机值。

例如

list = ["dog", "cat", "rat", "bird", "monkey"]

我想输出如下

{"dog": "bird", "cat": "monkey", "rat": "dog", "bird": "rat", "monkey": "cat"}

我想要的是

  • 一个值不能分配给自己,比如说不能是{"cat": "cat"}
  • 一个值只能分配一次,例如不能{"猫": "狗", "老鼠": "狗"}
  • 值不能相互分配,例如不能{"cat": "狗","狗","猫"}。

我试过这段代码,但很乱,我觉得这不是最好的方法。

def shuffle_recur(_list):
    final = {}
    not_done = copy.deepcopy(_list)
    for value in _list:
        without_list = not_done.copy()
        if value in without_list :
            without_list.remove(value)
        if value in final.values():
            for final_key, final_value in final.items():
                if final_value == value:
                    print(final_value, '    ', final_key)
                    if final_key in without_list :
                        without_list.remove(final_key)
        if len(without_list) < 1:
            print('less')
            return shuffle_recur(_list)
        target = random.choice(without_list)
        not_done.remove(target)
        final[value] = target
        print('{} >> {}'.format(value, target))
    return final

但它很乱,我不认为这是最好的方法。 有什么更好的方法吗?

python random
5个回答
1
投票

你可以只建立一个随机排序的项目列表,然后将它们作为键值配对。

从一方面你将采取的列表,在另一方面相同的列表旋转从上项 values[1:] + [values[0]]你将两者压缩成2乘2的对子,并从这些对子中建立一个听写器

values = ["dog", "cat", "rat", "bird", "monkey"]
shuffle(values)
result = dict(zip(values, values[1:] + [values[0]]))

例子

  • 洗牌 ['bird', 'dog', 'rat', 'monkey', 'cat']

  • 旋转产生 ['dog', 'rat', 'monkey', 'cat', 'bird']

  • 拉链 [('bird', 'dog'), ('dog', 'rat'), ('rat', 'monkey'), ('monkey', 'cat'), ('cat', 'bird')]

  • 那么每一对都会成为一个映射

print(values)  # ['bird', 'dog', 'rat', 'monkey', 'cat']
print(result)  # {'bird': 'dog', 'dog': 'rat', 'rat': 'monkey', 'monkey': 'cat', 'cat': 'bird'}

如果你不想让映射互相跟随,只需用以下方法 shuffle 二次

mappings = list(zip(values, values[1:] + [values[0]]))
shuffle(mappings)
result = dict(mappings)

1
投票

你可以对数据进行洗牌,然后随机生成周期长度来连接元素,直到你的列表用完为止。对于5个或更少元素的列表,需要创建一个全长的循环,以满足所有的要求(不能拆成4+1,因为1个元素没有伙伴,也不能拆成3+2,因为2个元素需要映射到自己身上,因此违反了要求#3)。对于长度为>=6的列表,我们可以随机选择最小长度为3的子周期。

import random

def random_mapping(data):
    data = data.copy()
    random.shuffle(data)
    result = {}
    while len(data) >= 5:
        index = random.randint(3, len(data)-2)  # length of the (sub-)cycle
        if index == len(data)-2:  # this means a full cycle is generated
            index = len(data)
        cycle, data = data[:index], data[index:]
        result.update(zip(cycle, cycle[1:]))
        result[cycle[-1]] = cycle[0]
    return result

0
投票
# used for shuffling
import random

def shuffle_recur(list1):
    # the final dictionary
    final = {}
    # needed for values as list1 are the keys
    list2 = copy.deepcopy(list1)
    random.shuffle(list2)
    # loop trough and assign values
    for i in range(len(list1)):
        final[list1[i]] = list2[i]
    return final

0
投票

你可以使用下面的:

ll = ["dog", "cat", "rat", "bird", "monkey"]

res = list(zip(ll, ll[1:] + ll[:1]))
print(dict(res)) 
# {'dog': 'cat', 'cat': 'rat', 'rat': 'bird', 'bird': 'monkey', 'monkey': 'dog'}

zip 函数可以用来提取列表上的对,而切片可以用来将当前元素与下一个元素连续配对,以实现高效配对。


0
投票

你可以用简单的索引运算来实现。

>>> li=["dog", "cat", "rat", "bird", "monkey"]
>>> dict((li[i],li[(i+1)%len(li)]) for i in range(len(li)))
{'dog': 'cat', 'cat': 'rat', 'rat': 'bird', 'bird': 'monkey', 'monkey': 'dog'}

或者,用同样的算术来理解听写。

{li[i]:li[(i+1)%len(li)] for i in range(len(li))}
# same result

你可能需要做 li 一组来重复复制,您可以使用 洗牌 如果你想要一个随机的顺序。

进一步解释。

  1. dict 创建一个字典,在本例中是由一个生成器创建元组。
  2. (li[i],li[(i+1)%len(li)]) 取列表中的两个元素并创建一个元组。列表中取两个元素并创建一个元组。%len(li) 绕到 0 在列表末尾,所以你有 ('dog','cat'),('cat','rat')...
  3. 最后一个元组是 (li[last_element], li[first_element]) 因为 li[(i+1)%len(li)] 算术。
© www.soinside.com 2019 - 2024. All rights reserved.