生成所有唯一的三元组



有一系列三元组:

[[1, 2, 3], [4, 5, 6], [7, 8, 9], [10, 11, 12],[13, 14, 15]]

(可以比这更长(。它们都是独一无二的。

问:生成这些三元组的所有可能组合的有效方法是什么,以使以前遇到的项目都不会再次"相遇"?

因此,例如,在此序列中,三元组不包含之前遇到的任何项目:

[[1, 2, 3], [4, 5, 6], [7, 8, 9], [10, 11, 12],[13, 14, 15]]
[[1, 5, 9], [4, 8, 12], [7, 11, 15], [10, 14, 3],[2, 6, 13]]
[[1, 4, 7], [5, 8, 11], [9, 12, 15], [10, 13, 2],[14, 3, 6]]

但是这个行不通:

[[1, 5, 9], [4, 6, 12], [7, 11, 15], [10, 14, 3],[2, 8, 13]]

因为第二个三元组的46以前一直在同一个三胞胎中,特别是在第一张记录的[4, 5, 6]

我认为可以通过使用random.sample(l, 3)从初始序列中随机选择三元组来完成,然后检查这个三元组以前是否没有使用过,但它看起来效率很低,我想知道是否有更好的方法。

更新:::

我意识到发布一个丑陋和低效的代码仍然有效是有意义的,只是为了说明我在说什么:

import random
import itertools
z = list(range(1, 10))
group_size = 3
superset = list()

def check_not_met(x):
for i in superset:
if set(x).issubset(set(i)):
return False
return True

def check_not_anyone_met(x):
for i in itertools.combinations(x, 2):
if not check_not_met(i):
return False
return True

subsession_matrices = list()

def generating_subsession(seq):
subglobal = list()
while seq:
x = a[-group_size:]
if check_not_anyone_met(x):
subglobal.append(x)
else:
return False
del seq[-group_size:]
return subglobal
for j in range(10000):
a = z.copy()
random.shuffle(a)
subsession_matrix = generating_subsession(a)
if not subsession_matrix:
continue
else:
subsession_matrices.append(subsession_matrix)
superset.extend(subsession_matrix)
print(subsession_matrices)

输出为:

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

好吧,这开始是一个评论,但它太大了,没有用。

首先,根据您的定义,没有唯一的组合。让我解释一下:

因为,您不想重复任何已经出现在三元组中的 2 个数字,它们出现的顺序很重要并更改组合。

举个例子来说明:

鉴于您从以下方面开始:

[[1, 2, 3], [4, 5, 6], [7, 8, 9], [10, 11, 12], [13, 14, 15]]

一个可能的序列(与您的序列不同(可能是:

[[1, 2, 3], [4, 5, 6], [7, 8, 9], [10, 11, 12], [13, 14, 15]]
[[1, 5, 10], [4, 8, 12], [7, 11, 15], [9, 14, 3],[ 2, 6, 13]]

(只需在第二个组合中将9换成10(。虽然这使得15在同一个三元组中再次无法使用,因此在该序列中您的第二个组合

[[1, 5, 9], [4, 8, 12], [7, 11, 15], [10, 14, 3],[2, 6, 13]]

不能出现在我的序列中。

那么,您如何定义唯一性?我认为你的定义有问题。我什至不确定顺序对序列的长度有任何影响。

检查此三元组以前是否未使用过

如果您对唯一序列不感兴趣,而是希望将限制应用于序列并获得尽可能多的组合,那么上述方法将不起作用。您应该检查三元组中是否包含 2 个数字,而不是之前是否出现过三元组。您的标准将无法识别组合

[[1, 5, 9], [4, 7, 13], [8, 11, 15], [10, 14, 3], [2, 6, 12]]

是不可接受的,尽管所有三胞胎以前都没有出现过。

希望这有帮助。无论如何,如果我误解了某些内容,请进行编辑。

您可以递归地将每个数字逐个填充到三元组列表中,同时跟踪每个数字在集合字典中看到的数字,如果它设法填写了所有数字,则返回组合。使用while循环继续执行此操作,直到找不到更多组合:

from copy import deepcopy
def unique(items, size=3):
def find_unique(items, size, seen, filled):
filled_set = set(item for group in filled for item in group)
if len(filled_set) == len(items):
return filled, seen
candidates = items - filled_set
if not filled or len(filled[-1]) == size:
filled.append([])
for incumbent in filled[-1]:
candidates -= seen[incumbent]
new_seen = deepcopy(seen)
new_filled = deepcopy(filled)
for candidate in candidates:
for incumbent in new_filled[-1]:
new_seen[incumbent].add(candidate)
new_seen[candidate].update(filled[-1])
new_filled[-1].append(candidate)
combinations, real_seen = find_unique(items, size, new_seen, new_filled)
if combinations:
return combinations, real_seen
del new_filled[len(filled):]
del new_filled[-1][len(filled[-1]):]
for incumbent in new_filled[-1]:
new_seen[candidate].remove(incumbent)
new_seen[incumbent].remove(candidate)
return None, None
combinations = [items]
seen = {}
for group in items:
for item in group:
seen.setdefault(item, set()).update(group)
while True:
combination, seen = find_unique(seen.keys(), size, seen, [])
if not combination:
break
combinations.append(combination)
return combinations

因此:

unique([[1, 2, 3], [4, 5, 6], [7, 8, 9], [10, 11, 12], [13, 14, 15]])

将返回:

[[[1, 2, 3], [4, 5, 6], [7, 8, 9], [10, 11, 12], [13, 14, 15]],
[[1, 4, 7], [2, 5, 8], [3, 10, 13], [6, 11, 14], [9, 12, 15]],
[[1, 5, 9], [2, 4, 10], [3, 6, 15], [7, 11, 13], [8, 12, 14]],
[[1, 6, 8], [2, 7, 14], [3, 9, 11], [4, 12, 13], [5, 10, 15]],
[[1, 10, 14], [2, 11, 15], [3, 4, 8], [5, 7, 12], [6, 9, 13]]]

您可以创建一个递归函数:

d = [[1, 2, 3], [4, 5, 6], [7, 8, 9], [10, 11, 12],[13, 14, 15]]
def create_triplet(nums, original, current = []):
if len(current) == 3:
yield sorted(current)
else:
for i in nums:
yield from create_triplet(nums, original, current+[i])
_original = [d]
def triplets(source, current=[]):
if len(current) == len(d):
_original.append(current)
yield current
else:
_flattened, seen = [i for b in current for i in b], []
_options = list(create_triplet([i for i in source if i not in current], _original))
for i in _options:
if i not in seen and all(all(c not in b for c in i) for b in current) and all(i not in c for c in _original):
_test = current+[i]
if all(all(sum(h in c for h in i) < 2 for i in _test for c in b) for b in _original):
yield from triplets(source, current=_test)
seen.append(i)
_ = list(triplets([i for b in d for i in b]))
print(_original)

输出:

[[1, 2, 3], [4, 5, 6], [7, 8, 9], [10, 11, 12], [13, 14, 15]]
[[1, 4, 7], [2, 5, 8], [3, 10, 13], [6, 11, 14], [9, 12, 15]]
[[1, 5, 9], [2, 4, 10], [3, 6, 15], [7, 11, 13], [8, 12, 14]]
[[1, 6, 8], [2, 7, 14], [3, 9, 11], [4, 12, 13], [5, 10, 15]]
[[1, 10, 14], [2, 11, 15], [3, 4, 8], [5, 7, 12], [6, 9, 13]]

最新更新