唯一对的组,每个组中成员出现一次

时间:2019-06-03 13:41:35

标签: python grouping itertools

我有此代码:

from itertools import groupby
from itertools import combinations


teams = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
combo = list(combinations(teams, 2))

输出是45个元组的列表。

[(1, 2), (1, 3), (1, 4), (1, 5), (1, 6), (1, 7), (1, 8), (1, 9), (1, 10), (2, 3), (2, 4), (2, 5), (2, 6), (2, 7), (2, 8), (2, 9), (2, 10), (3, 4), (3, 5), (3, 6), (3, 7), (3, 8), (3, 9), (3, 10), (4, 5), (4, 6), (4, 7), (4, 8), (4, 9), (4, 10), (5, 6), (5, 7), (5, 8), (5, 9), (5, 10), (6, 7), (6, 8), (6, 9), (6, 10), (7, 8), (7, 9), (7, 10), (8, 9), (8, 10), (9, 10)]

我想将45个元组分为9组,每组5个元组,每个组都是唯一的项。例如这样的

list_1 = [(1, 2), (3, 4), (5, 6), (7, 8), (9, 10)]
list_2 = [(1, 3), (2, 4), (5, 7), (6, 9), (8, 10)]
list_3 = 
list_4 = 
list_5 = 

因此,每个列表都包含元组,其中的项从1到10,没有重复。

7 个答案:

答案 0 :(得分:5)

这是一种基于round robin tournament scheduling algorithm的相当简单的方法。基本上,此方法将列表分为两半,并将列表的前半部分与列表后半部分的反向版本配对。然后,对于每个阶段,它都会“轮换”除列表中的第一支球队之外的所有球队(基于阶段或轮次的循环和列表串联正在模拟轮换)。

import ipaddress
srcIp = ipaddress.ip_network(str('10.0.0.0/24'))

答案 1 :(得分:2)

尝试一下:

d = {}
for i in combo:
    s = set(teams) - set(i)
    d[i] = [list(s)[k:k+2] for k in range(0, len(s), 2)]

输出

{(5, 9): [[1, 2], [3, 4], [6, 7], [8, 10]], (4, 7): [[1, 2], [3, 5], [6, 8], [9, 10]], (1, 3): [[2, 4], [5, 6], [7, 8], [9, 10]], (4, 8): [[1, 2], [3, 5], [6, 7], [9, 10]], (5, 6): [[1, 2], [3, 4], [7, 8], [9, 10]], (2, 8): [[1, 3], [4, 5], [6, 7], [9, 10]], (6, 9): [[1, 2], [3, 4], [5, 7], [8, 10]], (8, 9): [[1, 2], [3, 4], [5, 6], [7, 10]], (1, 6): [[2, 3], [4, 5], [7, 8], [9, 10]], (3, 7): [[1, 2], [4, 5], [6, 8], [9, 10]], (2, 5): [[1, 3], [4, 6], [7, 8], [9, 10]], (5, 8): [[1, 2], [3, 4], [6, 7], [9, 10]], (1, 2): [[3, 4], [5, 6], [7, 8], [9, 10]], (4, 9): [[1, 2], [3, 5], [6, 7], [8, 10]], (2, 9): [[1, 3], [4, 5], [6, 7], [8, 10]], (3, 10): [[1, 2], [4, 5], [6, 7], [8, 9]], (6, 10): [[1, 2], [3, 4], [5, 7], [8, 9]], (8, 10): [[1, 2], [3, 4], [5, 6], [7, 9]], (1, 5): [[2, 3], [4, 6], [7, 8], [9, 10]], (3, 6): [[1, 2], [4, 5], [7, 8], [9, 10]], (1, 10): [[2, 3], [4, 5], [6, 7], [8, 9]], (7, 9): [[1, 2], [3, 4], [5, 6], [8, 10]], (4, 10): [[1, 2], [3, 5], [6, 7], [8, 9]], (2, 6): [[1, 3], [4, 5], [7, 8], [9, 10]], (7, 10): [[1, 2], [3, 4], [5, 6], [8, 9]], (4, 5): [[1, 2], [3, 6], [7, 8], [9, 10]], (1, 4): [[2, 3], [5, 6], [7, 8], [9, 10]], (2, 10): [[1, 3], [4, 5], [6, 7], [8, 9]], (9, 10): [[1, 2], [3, 4], [5, 6], [7, 8]], (3, 9): [[1, 2], [4, 5], [6, 7], [8, 10]], (2, 3): [[1, 4], [5, 6], [7, 8], [9, 10]], (1, 9): [[2, 3], [4, 5], [6, 7], [8, 10]], (6, 8): [[1, 2], [3, 4], [5, 7], [9, 10]], (6, 7): [[1, 2], [3, 4], [5, 8], [9, 10]], (3, 5): [[1, 2], [4, 6], [7, 8], [9, 10]], (2, 7): [[1, 3], [4, 5], [6, 8], [9, 10]], (5, 10): [[1, 2], [3, 4], [6, 7], [8, 9]], (4, 6): [[1, 2], [3, 5], [7, 8], [9, 10]], (7, 8): [[1, 2], [3, 4], [5, 6], [9, 10]], (5, 7): [[1, 2], [3, 4], [6, 8], [9, 10]], (3, 8): [[1, 2], [4, 5], [6, 7], [9, 10]], (1, 8): [[2, 3], [4, 5], [6, 7], [9, 10]], (1, 7): [[2, 3], [4, 5], [6, 8], [9, 10]], (3, 4): [[1, 2], [5, 6], [7, 8], [9, 10]], (2, 4): [[1, 3], [5, 6], [7, 8], [9, 10]]}

答案 2 :(得分:2)

我对这个问题的看法:

from itertools import combinations

teams = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
combo = list(combinations(teams, 2))

sets = []

def is_combo_value_in_set(c, s):
    for val in c:
        for val_s in s:
            for v in val_s:
                if val == v:
                    return True
    return False

for c in combo:
    should_add_set = True
    for current_set in sets:
        if is_combo_value_in_set(c, current_set) is False:
            should_add_set = False
            current_set.add(c)
            break
    if should_add_set:
        sets.append(set())
        sets[-1].add(c)

for v in sets:
    print(sorted(v))

打印:

[(1, 2), (3, 4), (5, 6), (7, 8), (9, 10)]
[(1, 3), (2, 4), (5, 7), (6, 8)]
[(1, 4), (2, 3), (5, 8), (6, 7)]
[(1, 5), (2, 6), (3, 7), (4, 8)]
[(1, 6), (2, 5), (3, 8), (4, 7)]
[(1, 7), (2, 8), (3, 5), (4, 6)]
[(1, 8), (2, 7), (3, 6), (4, 5)]
[(1, 9), (2, 10)]
[(1, 10), (2, 9)]
[(3, 9), (4, 10)]
[(3, 10), (4, 9)]
[(5, 9), (6, 10)]
[(5, 10), (6, 9)]
[(7, 9), (8, 10)]
[(7, 10), (8, 9)]

编辑:

也许不是最有效的解决方案,但它可以工作。我们随机选择5个匹配项,直到匹配项唯一,然后将其添加到结果列表中:

from itertools import combinations, chain
from random import choice

teams = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
combo = list(combinations(teams, 2))

available = combo.copy()
rv = []

def random_pop(l):
    ch = choice(l)
    l.remove(ch)
    return ch

num_tries = 0

while True:
    num_tries += 1
    if num_tries > 99999:
        available = combo.copy()
        rv = []
        num_tries = 0

    l = [random_pop(available), random_pop(available), random_pop(available), random_pop(available), random_pop(available)]
    flat = list(chain.from_iterable(l))
    if len(set(flat)) == len(flat):
        #is unique
        rv.append(l)
    else:
        for i in l:
            available.append(i)
    if len(available) == 0:
        break

for l in rv:
    print(sorted(l))

打印(例如):

[(1, 8), (2, 4), (3, 5), (6, 10), (7, 9)]
[(1, 5), (2, 7), (3, 6), (4, 9), (8, 10)]
[(1, 10), (2, 6), (3, 8), (4, 7), (5, 9)]
[(1, 3), (2, 9), (4, 8), (5, 6), (7, 10)]
[(1, 9), (2, 3), (4, 6), (5, 10), (7, 8)]
[(1, 4), (2, 5), (3, 7), (6, 8), (9, 10)]
[(1, 7), (2, 10), (3, 4), (5, 8), (6, 9)]
[(1, 6), (2, 8), (3, 9), (4, 10), (5, 7)]
[(1, 2), (3, 10), (4, 5), (6, 7), (8, 9)]

答案 3 :(得分:2)

每个团队出现9次,因此您至少需要9个列表(回合),以确保所有45对都出现在一个非重复列表中。如果我们允许每个列表使用不同数量的游戏,那么无需重复就可以轻松生成游戏列表。但是,如果您希望9个列表中的每个列表有5个游戏,则需要使用更复杂的算法。

这里有这样一种算法:https://nrich.maths.org/1443

这是Python中的算法示例(适用于偶数和奇数组):

def roundRobin(teams):
    result    = []
    count     = len(teams)
    even      = 1-(count&1)
    poly      = teams[even:]
    for _ in range(count-even):
        games  = [(teams[0],poly[0])]*even
        games += [(poly[i],poly[count-i-even]) for i in range(1,(count+1)//2)]
        result.append(games)
        poly = poly[1:]+poly[:1]
    return result

# Odd number of teams (7) 
for games in roundRobin(["A","B","C","D","E","F","G"]):
    print(games)
# [('B', 'G'), ('C', 'F'), ('D', 'E')] ("A" sits out)
# [('C', 'A'), ('D', 'G'), ('E', 'F')] ("B" sits out)
# [('D', 'B'), ('E', 'A'), ('F', 'G')] ("C" sits out)
# [('E', 'C'), ('F', 'B'), ('G', 'A')] ("D" sits out)
# [('F', 'D'), ('G', 'C'), ('A', 'B')] ("E" sits out)
# [('G', 'E'), ('A', 'D'), ('B', 'C')] ("F" sits out)
# [('A', 'F'), ('B', 'E'), ('C', 'D')] ("G" sits out)

# Even number of teams (10)
for games in roundRobin(["A","B","C","D","E","F","G","H","I","J"]):
    print(games)     
# [('A', 'B'), ('C', 'J'), ('D', 'I'), ('E', 'H'), ('F', 'G')]
# [('A', 'C'), ('D', 'B'), ('E', 'J'), ('F', 'I'), ('G', 'H')]
# [('A', 'D'), ('E', 'C'), ('F', 'B'), ('G', 'J'), ('H', 'I')]
# [('A', 'E'), ('F', 'D'), ('G', 'C'), ('H', 'B'), ('I', 'J')]
# [('A', 'F'), ('G', 'E'), ('H', 'D'), ('I', 'C'), ('J', 'B')]
# [('A', 'G'), ('H', 'F'), ('I', 'E'), ('J', 'D'), ('B', 'C')]
# [('A', 'H'), ('I', 'G'), ('J', 'F'), ('B', 'E'), ('C', 'D')]
# [('A', 'I'), ('J', 'H'), ('B', 'G'), ('C', 'F'), ('D', 'E')]
# [('A', 'J'), ('B', 'I'), ('C', 'H'), ('D', 'G'), ('E', 'F')]

答案 4 :(得分:1)

我认为以下代码将起作用:

import copy


def extract_one_list(xdata):
    """
    `xdata` .......... `external data`
    """
    old_type = type(xdata[0])
    # we are going to be testing for whether
    # two tuples have any elements in common.
    # For example, do (4, 5) and (7, 8) have any elements common?
    # the answer is `no`.
    prohibited_elements = set(xdata.pop(0))
    iout = [copy.copy(prohibited_elements)]
    # `iout`.......... `internal output`
    candi = 0
    while True:
        # `candi`......... candidate index
        # `candy`......... candidate
        if candi >= len(xdata):
            break
        candy = set(xdata[candi])
        if len(prohibited_elements.intersection(candy)) == 0:
            iout.append(candy)
            prohibited_elements.update(xdata.pop(candi))
        candi = candi + 1

    # Next, convert sets into the type of container
    # which was originally used (tuples, lists,
    # or some other type of container
    # Let external iout (xout) be:
    # the old_type of the internal element (ielem)
    # for each internal element in the internal iout (iout)
    xout = [old_type(ielem) for ielem in iout]
    return xout

def extract_all_lists(xdata):
    lol = list()
    # `lol`...... `list of lists`
    while len(xdata) > 0:
        lyst = extract_one_list(unsorted_data)
        lol.append(lyst)
    return lol

unsorted_data = [(1, 2), (1, 3), (1, 4), (1, 5), (1, 6),
                 (1, 7), (1, 8), (1, 9), (1, 10), (2, 3),
                 (2, 4), (2, 5), (2, 6), (2, 7), (2, 8),
                 (2, 9), (2, 10), (3, 4), (3, 5), (3, 6),
                 (3, 7), (3, 8), (3, 9), (3, 10), (4, 5),
                 (4, 6), (4, 7), (4, 8), (4, 9), (4, 10),
                 (5, 6), (5, 7), (5, 8), (5, 9), (5, 10),
                 (6, 7), (6, 8), (6, 9), (6, 10), (7, 8),
                 (7, 9), (7, 10), (8, 9), (8, 10), (9, 10)]

lol = extract_all_lists(unsorted_data)
print('\n'.join([str(x) for x in lol]))

输出为:

[(1, 2), (3, 4), (5, 6), (8, 7), (9, 10)]
[(1, 3), (2, 4), (5, 7), (8, 6)]
[(1, 4), (2, 3), (8, 5), (6, 7)]
[(1, 5), (2, 6), (3, 7), (8, 4)]
[(1, 6), (2, 5), (8, 3), (4, 7)]
[(1, 7), (8, 2), (3, 5), (4, 6)]
[(8, 1), (2, 7), (3, 6), (4, 5)]
[(1, 9), (2, 10)]
[(1, 10), (9, 2)]
[(9, 3), (10, 4)]
[(10, 3), (9, 4)]
[(9, 5), (10, 6)]
[(10, 5), (9, 6)]
[(9, 7), (8, 10)]
[(10, 7), (8, 9)]

答案 5 :(得分:1)

您可以使用递归来生成包含groupingBy()的所有元素的partitionBy()组合,然后使用迭代器进行过滤:

for (Map.Entry<String, Response> entry: responses.entrySet()) {
    String key = entry.getKey();
    Response value = entry.getValue();
    if (key.equals("foo") && !value.equals("bar")) {
        res1 = value;
    } else if (key.equals("some other key")) {
        res2 = value;
    }
}

Response finalResponse = res1 != null ? res1 : res2;

输出:

Optional<Response> res1 = Optional.empty();
Response res2;

res1 = responses.entrySet().stream()
        .filter(entry -> entry.getKey().equals("foo") && 
                !entry.getValue().equals("bar"))
        .map(Map.Entry::getValue)
        .findFirst();
res2 = responses.entrySet().stream()
        .filter(entry -> entry.getKey().equals("some other key"))
        .map(Map.Entry::getValue)
        .findFirst().orElse(null);

Response finalResponse = res1.orElse(res2);

答案 6 :(得分:0)

除非我缺少有关此问题的信息,也许使用frozenset s这样的东西可以做到吗?

from itertools import combinations


teams = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
games = set(frozenset(combo) for combo in combinations(teams, 2))
brackets = []

while games:
    bracket = []
    while games and len(bracket) < 5:
        bracket.append(tuple(sorted(games.pop())))
    brackets.append(bracket)

for bracket in brackets:
    print(bracket)

输出(例如)

[(4, 10), (2, 8), (1, 4), (4, 6), (2, 3)]
[(3, 9), (2, 6), (4, 5), (7, 9), (7, 8)]
[(4, 9), (1, 10), (2, 9), (5, 9), (3, 4)]
[(6, 9), (1, 7), (7, 10), (8, 10), (2, 4)]
[(1, 8), (5, 6), (3, 5), (1, 6), (5, 8)]
[(1, 3), (4, 7), (3, 7), (6, 7), (3, 6)]
[(3, 8), (1, 5), (6, 8), (5, 10), (2, 7)]
[(5, 7), (1, 9), (2, 10), (9, 10), (1, 2)]
[(8, 9), (6, 10), (2, 5), (3, 10), (4, 8)]