Выберите из списка пар комбинаций кортежей, чтобы каждый элемент кортежа появлялся как минимум дважды - PullRequest
0 голосов
/ 09 ноября 2018

Предположим, у меня есть список кортежей, элементами которых являются все возможные пары из списка:

т.е. matchup=[('Mike','John'),('Mike','Mary'),('Mike','Jane'),('John','Mary'),('John','Jane'),('Mary','Jane')...]

Я бы хотел сократить список так, чтобы имя каждого человека появлялось дважды независимо от того, является ли он первым элементом в паре или вторым. Элемент кортежа может быть выбран более двух раз, если невозможно создать новую пару без этого.

Заранее спасибо.

редактирование: Первоначально в списке я использовал цикл for, чтобы связать каждого человека с другим человеком наугад ала:

list=["John","Mike","Mary","Jane"]
pairing=[]
for person in list:
    for i in range(2):
        person2=random.sample(list(list),1)
        this_match=str(person)+str(person2)
        while this_match in pairing:
            person2=random.sample(list(list),1)
            this_match=str(person)+str(person2)
        pairing.append(this_match)

Это привело к дублированию того же человека. Моя вторая попытка такая:

from itertools import combinations
import pandas as pd
from collections import Counter

possible_games = combinations(list, 2)

games = list(possible_games)
dupe_check=Counter(games)
print(dupe_check)
print (games, len(games))

Однако я не могу уменьшить элементы каждого кортежа, чтобы они выглядели как можно ближе к двум разам.

Один из возможных выводов может выглядеть следующим образом:

[('Mike','John'),('Mike','Mary'),('John','Mary'),("Mary","Jane"),("Jane","Mike")]

Джон появляется дважды. Джейн появляется дважды. Майк появляется три раза, чтобы Джейн появилась дважды. Мэри появляется три раза, а Джейн появляется дважды.

Ответы [ 2 ]

0 голосов
/ 09 ноября 2018

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

lst = ["John", "Mike", "Mary", "Jane"]  # not shadowing 'list'

pairs = list(zip(lst, lst[1:]+lst[:1]))
pairs
# [('John', 'Mike'), ('Mike', 'Mary'), ('Mary', 'Jane'), ('Jane', 'John')]

По сути, это обводит список и объединяет каждый элемент с двумя соседями. Если вам нужно больше случайности, вы можете перемешать список заранее или разбить список на куски и применить его к кускам.

0 голосов
/ 09 ноября 2018

Следующий код полностью решит вашу проблему.result даст вам ответ в этом коде.

import itertools
import random
import numpy as np

# lst is a list of names that I have chosen.
lst = ['Apple', 'Boy', 'Cat', 'Dog', 'Eagle']

# create a list of tuples (pairs of names).
matchup = list(itertools.product(lst, lst)) 

# randomly shuffle the pairs of names.
random.shuffle(matchup)


def func(inp):
    out = []
    out += [ inp[0] ]

    # Unique array of names.
    unq = np.unique( (zip(*inp))[0] )

    # Stores counts of how many times a given name features in the final list of tuples.
    counter = np.zeros(len(unq))

    indx0 = np.where( out[0][0]==unq )[0][0]
    indx1 = np.where( out[0][1]==unq )[0][0]    
    counter[indx0]+=1
    counter[indx1]+=1    

    reserve = []

    #first try of filling output list with tuples so that no name enters the output list more than once.   
    for i in range(1,len(matchup)):
        tup = matchup[i]

        indx0 , indx1 = np.where(tup[0]==unq)[0][0], np.where(tup[1]==unq)[0][0]

        temp = counter.copy()

        temp[indx0]+=1
        temp[indx1]+=1

        if ( (temp[indx0]<=2) and (temp[indx1]<=2) ):
            out += [tup]
            counter[indx0]+=1
            counter[indx1]+=1

        else: reserve += [tup]     

    #A tuple element may be selected more than twice if it is not possible to create a new pair without doing so.    
    while(np.any(counter==1)):
        tup = reserve[0]

        indx0 , indx1 = np.where(tup[0]==unq)[0][0], np.where(tup[1]==unq)[0][0]

       # Create a copy of counter array. 
       temp = counter.copy()

        if ( (temp[indx0]<2) or (temp[indx1]<2) ):
            out += [tup]
            counter[indx0]+=1
            counter[indx1]+=1 

        reserve.pop(0)    

    return out  

result = func(matchup)
print (result)

Вывод result будет отличаться в разных прогонах, поскольку список кортежей (имен) случайным образом перетасовывается при каждом прогоне.Одним из примеров результата является следующее.

[('Cat', 'Dog'), ('Eagle', 'Boy'), ('Eagle', 'Dog'), ('Cat', 'Boy'), ('Apple', 'Apple')]      
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...