Вот логически масштабируемое решение, которое для n
словарей, сравниваемых по m
значениям, потребует времени n*m
для оценки.
Обратите внимание, если три совпадения, я верну группу3. Достаточно просто взорвать это для всех подходящих пар.Но если вы сделаете это, то можете вернуть что-то размером n*n
.Я показал вам, как выглядят оба.
def group_on(variables, *tracks):
# Build a trie first.
trie = {}
for track in tracks:
this_path = trie
for variable in variables:
value = track[variable]
if value not in this_path:
this_path[value] = {}
this_path = this_path[value]
if 'final' not in this_path:
this_path['final'] = [track]
else:
this_path['final'].append(track)
def find_groups(this_path, count):
if 0 == count:
if 1 < len(this_path['final']):
yield this_path['final']
else:
for next_path in this_path.values():
for group in find_groups(next_path, count-1):
yield group
for group in find_groups(trie, len(variables)):
yield group
def group_to_pairs(group):
for i in range(len(group)-1):
for j in range(i+1, len(group)):
yield (group[i], group[j])
print('Efficient version')
for group in group_on(['tempo', 'key', 'mode'],
{'track': 1, 'tempo': 1, 'key': 'A', 'mode': 'minor'},
{'track': 2, 'tempo': 1, 'key': 'A', 'mode': 'major'},
{'track': 3, 'tempo': 1, 'key': 'A', 'mode': 'minor'},
{'track': 4, 'tempo': 1, 'key': 'A', 'mode': 'major'},
{'track': 5, 'tempo': 1, 'key': 'A', 'mode': 'minor'},
):
print(group)
print('Versus')
for group in group_on(['tempo', 'key', 'mode'],
{'track': 1, 'tempo': 1, 'key': 'A', 'mode': 'minor'},
{'track': 2, 'tempo': 1, 'key': 'A', 'mode': 'major'},
{'track': 3, 'tempo': 1, 'key': 'A', 'mode': 'minor'},
{'track': 4, 'tempo': 1, 'key': 'A', 'mode': 'major'},
{'track': 5, 'tempo': 1, 'key': 'A', 'mode': 'minor'},
):
for pair in group_to_pairs(group):
print(pair)