有一系列的三胞胎:
[[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]]
因为第二个三元组中的4
和6
之前曾经在同一个三元组中,特别是在第一条记录的[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]]
答案 0 :(得分:1)
好的,这是从评论开始的,但是太大而无法使用。
首先,根据您的定义,没有唯一的组合。让我解释一下:
从那时起,您就不想重复已经出现在三联体中的任何两个数字,它们出现的顺序很重要,并且不会更改组合。
一个清楚的例子:
首先,您应该:
[[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
)。不过,这会使1
和5
在同一三元组中再次不可用,因此按此顺序,您的第二个组合
[[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]]
尽管所有三胞胎以前都没有出现,但是不可接受的。
希望这会有所帮助。无论如何,如果我误解了一些内容,请进行编辑。
答案 1 :(得分:1)
您可以将每个数字递归地填写到三胞胎列表中,同时跟踪每个数字在集合字典中看到的数字,并在设法填写所有数字的情况下返回组合。使用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]]]
答案 2 :(得分:1)
您可以创建一个递归函数:
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]]