【发布时间】:2021-06-18 06:23:21
【问题描述】:
我需要一个高效的 Python 算法来获得以下结果:
示例 1:
l = [[1, 2, 3, 4], [2, 1, 4], [3, 1], [4, 1, 2]]
r = [[1, 2, 4], [3]]
示例 2:
l = [[1, 2, 3, 4], [2, 1], [3, 1], [4, 1]]
r = [[1, 2], [3], [4]]
示例 3:
l = [[1], [2, 3, 4], [3, 2, 5, 6], [4, 2] , [5, 3], [6, 3]]
r = [[2, 3], [1], [4], [5], [6]]
在这些示例中,l 是列表的列表,其中:
- 每个列表的第一个元素始终是该元素的索引
- 如果元素 1 包含值 3,则轮到第三个列表将始终包含 1 本身。
我需要找到一种使用 3 个标准对匹配子集进行分组的有效方法:子集的长度、子元素的频率以及子元素只能是 1 个结果子集的一部分这一事实。
在第一个示例中,子元素 [1] 将是最频繁的子集,但更长的子集 [1, 2, 4] 出现在 4 个元素中的 3 个中这一事实更重要:长度胜过频率。
在第二个示例中,[1, 3] 等分组的长度和频率与 [1, 2] 相同,但 1 被第一个找到的子集“占用”。
后期编辑:
到目前为止我所做的是:
- 我把我的列表变成了字典
- 然后我构建了一个函数,该函数根据字典唯一键的所有可能排列重复构建匹配和不匹配值的方阵
- 然后在方阵中,我沿着主对角线搜索最大的方格(基于此处提供的代码:Python find the largest square in the matrix dynamic programming)
- 然后我消除重叠的最大方块并重新开始
我的代码完全没有效率,因为排列的数量随着我的初始字典的大小呈指数增长,因此我正在寻找一种新的想法,一种新的方法。
这是我到目前为止所做的:
from itertools import chain, permutations
def group_matches(my_dict, matched=None):
def update_my_dict(my_dict, matched):
ret_val = {}
for k, v in my_dict.items():
if k not in matched:
for unique_ind in matched:
if unique_ind in v:
v.remove(unique_ind)
ret_val[k] = v
return ret_val
def get_matches(unique_ind_permutation, my_dict):
def create_matrix(unique_ind_permutation, my_dict):
matrix = []
for k in unique_ind_permutation:
r = [True if f in my_dict[k] else False
for f in unique_ind_permutation]
matrix += [r]
return matrix
matrix = create_matrix(unique_ind_permutation, my_dict)
dp = [[0] * len(matrix) for _ in range(len(matrix))]
max_squares = [(0, None, None)]
for ri, r in enumerate(matrix):
for ci, c in enumerate(r):
dp[ri][ci] = 0 if not c \
else (1 if ri == 0 or ci == 0
else min(dp[ri - 1][ci], dp[ri][ci - 1], dp[ri - 1][ci - 1]) + 1)
max_squares = [(dp[ri][ci], ri, ci)] if dp[ri][ci] > max_squares[0][0] \
else (max_squares + [(dp[ri][ci], ri, ci)] if dp[ri][ci] == max_squares[0][0]
else max_squares)
matches = []
if max_squares[0][0] != 0:
for max_square in max_squares:
rows = [r for r in range(max_square[1]+1-max_square[0],max_square[1]+1)]
columns = [c for c in range(max_square[2]+1-max_square[0],max_square[2]+1)]
if rows == columns:
matches += [tuple(rows)]
matches = eliminate_common_matches(matches)
matches_to_unique_ind = []
l = 0
if len(matches) > 0:
l = len(matches[0])
for m in matches:
m_unique_ind = sorted([unique_ind_permutation[x] for x in m])
matches_to_unique_ind += [m_unique_ind]
return matches_to_unique_ind, l
def eliminate_common_matches(matches):
for m in matches:
aux = matches.copy()
aux.remove(m)
for a in aux:
common = (set(m) & set(a))
if len(common) > 0:
min_m = min(m)
min_a = min(a)
if min_m <= min_a:
matches.remove(a)
else:
matches.remove(m)
return matches
def find_matched(unique_indexes, matches):
matched = []
unmatched = []
for unique_ind in unique_indexes:
for m in matches:
if unique_ind in m:
matched += [unique_ind]
else:
unmatched += [unique_ind]
return matched, unmatched
if matched is not None:
my_dict = update_my_dict(my_dict, matched)
unique_indexes = list(my_dict.keys())
p_unique_indexes = list(permutations(unique_indexes))
matches = []
last_l = 0
for p in p_unique_indexes:
m, l = get_matches(p, my_dict)
if last_l < l:
matches.clear()
last_l = l
if last_l == l and l > 0:
matches += m
matches = set(tuple(l) for l in matches)
matches_order = []
for m in matches:
mx = sorted([unique_indexes.index(unique_ind_x) for unique_ind_x in m])
matches_order += [mx]
matches_order = eliminate_common_matches(matches_order)
matches = []
for mo in matches_order:
mx = [unique_indexes[x] for x in mo]
matches += [mx]
matched, unmatched = find_matched(unique_indexes, matches)
return matches, matched, unmatched
my_dict = {1:[1, 2, 3, 4],
2:[2, 1, 4],
3:[3, 1],
4:[4, 1, 2]}
unique_indexes = list(my_dict.keys())
matches = []
matched = None
while True:
instance_matches, matched, unmatched = group_matches(my_dict, matched)
if len(instance_matches) > 0:
matches += instance_matches
if len(unmatched) == 0 or len(instance_matches) == 0:
break
unmatched = list(set(unique_indexes) - set(list(chain(*matches))))
matches_unique = []
for i, x in enumerate(matches):
if x not in matches[:i]:
matches_unique += [x]
matches = matches_unique + unmatched
print(matches)
另一个更复杂的例子:
my_dict = {
'a':['a', 'b', 'c', 'h'],
'b':['b', 'a', 'c', 'i'],
'c':['c', 'a', 'b', 'd', 'e'],
'd':['d', 'c', 'e', 'f'],
'e':['e', 'c', 'd', 'f'],
'f':['f', 'd', 'e', 'g', 'h'],
'g':['g', 'f', 'h'],
'h':['h', 'a', 'f', 'g'],
'i':['i', 'b']
}
# expected outcome:
res = [['c', 'd', 'e'], ['f', 'g', 'h'], ['a', 'b'], ['i']]
子集 ['d', 'e', 'f'] 不是预期结果的一部分,因为 'd' 和 'e' 已经被第一个子集占用 .
【问题讨论】:
-
你的代码在哪里?到目前为止,您尝试过什么? @桑迪乙
-
如果您的输入总是像您的示例中那样简短,则不需要“高效算法”。如果您希望有大量输入,请考虑使用 Python 以外的其他工具,因为它的性能不是很好。
-
是的,我的输入可以变得更长。关于我还能使用什么的任何建议?谢谢。
-
我正在研究解决方案。对于第一个示例
l = [[1, 2, 3, 4], [2, 1, 4], [3, 1], [4, 1, 2]],为什么答案应该是r = [[1, 2, 4], [3]]而不是r = [[1, 2, 3, 4]],[1, 2, 3, 4]是比[1, 2, 4]更长的子序列? -
因为在结果中: 1. 任何子元素都不能出现多次:结果如[[1, 2, 3, 4]], [1, 2, 3, 4 ]] 将意味着例如 1、2 等总共出现两次。 2.我对最长的子序列不感兴趣,而是寻找最长频率最高的子序列,条件是长度胜过频率。
标签: python list grouping subset