繁体   English   中英

生成没有重复的每个组合的列表

[英]generating list of every combination without duplicates

我想生成一个组合列表。 我将尝试简化我的问题以使其易于理解。

我们有 3 个变量:

  • x:字母数
  • k:组数
  • n:每组字母数

我想使用 python 生成所有可能组合的列表,没有任何重复知道:我不关心组的顺序和组内字母的顺序。

例如,x = 4,k = 2,n = 2:

# we start with 4 letters, we want to make 2 groups of 2 letters
letters = ['A','B','C','D']

# here would be a code that generate the list

# Here is the result that is very simple, only 3 combinations exist.
combos = [ ['AB', 'CD'], ['AC', 'BD'], ['AD', 'BC'] ]

由于我不关心组内或组内的顺序以及组内的字母,因此['AB', 'CD']['DC', 'BA']是重复的。

这是我的实际问题的简化,它具有以下值: x = 12 , k = 4 , n = 3 我尝试使用itertools中的一些功能,但是由于组合太多,我的电脑死机了。

另一种看待问题的方式:你有 12 名球员,你想组成 4 支球队,每队 3 名球员。 所有的可能性是什么?

谁能帮我找到一个优化的解决方案来生成这个列表?

肯定会有更复杂/更有效的方法来执行此操作,但这里有一种方法可以在合理的时间内为您的示例工作,并且应该足够容易以适应其他情况。

它会根据您的规格生成独特的团队及其独特的组合。

from itertools import combinations

# this assumes that team_size * team_num == len(players) is a given
team_size = 3
team_num = 4
players = list('ABCDEFGHIJKL')
unique_teams = [set(c) for c in combinations(players, team_size)]

def duplicate_player(combo):
    """Returns True if a player occurs in more than one team"""
    return len(set.union(*combo)) < len(players)
    
result = (combo for combo in combinations(unique_teams, team_num) if not duplicate_player(combo))

result是一个生成器,可以使用list(result)迭代或转换为列表。 在 kaggle.com 上,生成所有可能组合的完整列表需要一分钟左右(总共 15400,与评论中@beaker 和 @John Coleman 的计算一致)。 这些团队是看起来像这样的集合的元组:

[({'A', 'B', 'C'}, {'D', 'E', 'F'}, {'G', 'H', 'I'}, {'J', 'K', 'L'}),
 ({'A', 'B', 'C'}, {'D', 'E', 'F'}, {'G', 'H', 'J'}, {'I', 'K', 'L'}),
 ({'A', 'B', 'C'}, {'D', 'E', 'F'}, {'G', 'H', 'K'}, {'I', 'J', 'L'}),
 ...
]

如果需要,您可以通过在每个字符串上调用''.join()将它们转换为字符串。

另一种解决方案(玩家编号为 0、1、...):

import itertools

def equipartitions(base_count: int, group_size: int):
    if base_count % group_size != 0:
        raise ValueError("group_count must divide base_count")

    return set(_equipartitions(frozenset(range(base_count)), group_size))


def _equipartitions(base_set: frozenset, group_size: int):
    if not base_set:
        yield frozenset()

    for combo in itertools.combinations(base_set, group_size):
        for rest in _equipartitions(base_set.difference(frozenset(combo)), group_size):
            yield frozenset({frozenset(combo), *rest})


all_combinations = [
    [tuple(team) for team in combo]
        for combo in equipartitions(12, 3)
]

print(all_combinations)
print(len(all_combinations))

还有一个:

import itertools
from typing import Iterable

def equipartitions(players: Iterable, team_size: int):
    if len(players) % team_size != 0:
        raise ValueError("group_count must divide base_count")

    return _equipartitions(set(players), team_size)


def _equipartitions(players: set, team_size: int):
    if not players:
        yield []
        return

    first_player, *other_players = players
    for other_team_members in itertools.combinations(other_players, team_size-1):
        first_team = {first_player, *other_team_members}
        for other_teams in _equipartitions(set(other_players) - set(first_team), team_size):
            yield [first_team, *other_teams]


all_combinations = [
    {''.join(sorted(team)) for team in combo} for combo in equipartitions(players='ABCDEFGHIJKL', team_size=3)
]


print(all_combinations)
print(len(all_combinations))

首先,您可以使用列表理解为您提供所有可能的组合(无论重复项如何):

comb = [(a,b) for a in letters for b in letters if a != b]

然后,您可以使用已排序的 function 对元组进行排序。 之后,要删除重复项,您可以将所有项目转换为一个集合,然后再转换回列表。

var = [tuple(sorted(sub)) for sub in comb]
var = list(set(var))

您可以使用列表理解方法,它的时间复杂度为 O(n*n-1),或者您可以使用更冗长的方式,但时间复杂度为 O(n^2-n)/2 :

comb = []

for first_letter_idx, _ in enumerate(letters):
    for sec_letter_idx in range(first_letter_idx + 1, len(letters)):
        comb.append(letters[first_letter_idx] + letters[sec_letter_idx])

print(comb)

comb2 = []

for first_letter_idx, _ in enumerate(comb):
    for sec_letter_idx in range(first_letter_idx + 1, len(comb)):
        if (comb[first_letter_idx][0] not in comb[sec_letter_idx]
        and comb[first_letter_idx][1] not in comb[sec_letter_idx]):
            comb2.append([comb[first_letter_idx], comb[sec_letter_idx]])

print(comb2)

该算法需要更多工作来处理动态输入。 也许递归。

使用 itertools 的组合

from itertools import combinations 

x = list(combinations(['A','B','C','D'],2))

t = []
for i in (x):
    t.append(i[0]+i[1]) # concatenating the strings and adding in a list

g = []
for i in range(0,len(t),2):
    for j in range(i+1,len(t)):
        g.append([t[i],t[j]])
        break
print(g)

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM