Случайным образом назначьте пару каждому элементу списка без повторений - PullRequest
5 голосов
/ 09 мая 2020

Итак, у меня есть список, и я хотел бы «присвоить» значения другому случайному значению.

Например,

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

Я хотел бы получить результат вроде

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

Я бы хотел:

  • Значение не может быть присвоено самому себе, например not {"cat": "cat"}
  • Значение может быть назначен только один раз, например, not {"cat": "dog", "rat": "dog"}
  • Значения не могут быть присвоены друг другу, например not {"cat": "dog", "dog", "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

Но это очень беспорядочно, и я не думаю, что это лучший способ. Что было бы лучше сделать это?

Ответы [ 5 ]

1 голос
/ 09 мая 2020

Вы можете перемешать данные, а затем произвольно сгенерировать длины цикла для соединения элементов, пока ваш список не будет исчерпан. Для списков с 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
1 голос
/ 09 мая 2020

Вы можете просто создать произвольно упорядоченный список ваших элементов, а затем объединить их как ключ-значение

С одной стороны вы возьмете список, с другой стороны тот же список, повернутый от элемента 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)
0 голосов
/ 09 мая 2020

Вы можете сделать это с помощью простой арифметики индексов c:

>>> 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'}

Или, понимания dict с той же арифметикой c:

{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)] арифметики c.
0 голосов
/ 09 мая 2020
# 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 голосов
/ 09 мая 2020

Вы можете использовать следующее:

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 функция может использоваться для извлечения пар по списку, а нарезка может использоваться для последовательного связывания текущего элемента со следующим для эффективного связывания .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...