使用键从不同列表中选择实体的唯一组合

时间:2016-03-05 00:06:30

标签: python

如果有人问过这个问题,我可能没有必要的词汇来找到正确的问题。

如果我有这样的等长列表(或元组):

[6, 4, 7] [gold, blue, red] [dog, cat, echidna] [hot, cold, rainy]

一组键,它们是已知范围内的连续整数,等于唯一组合的数量(在本例中为81)。

是否可以从每个列表中为每个键选择一个项目,以确保组合是唯一的? (并从组合中获取密钥)。

这样

0可能会产生(6,金,猫,热)

1可能会产生(猫,4,金,雨)

2可能会产生(热,红,针鼹,7)

等...

并且知道(热,红,针鼹,7)是2?

产生的选择

假设已知并修复了列表的长度和顺序,列表中的项目保证在每个列表和所有列表中是唯一的,并且每个列表都可以排序/排序

3 个答案:

答案 0 :(得分:1)

所有列表中的所有元素都是唯一的

如果输入值在不同列表中都是唯一的,那么您可以。减少元素以减少输出

import itertools

input = [[6, 4], ['gold', 'blue'], ['dog', 'cat'], ['hot', 'cold']];
output = list(itertools.product(*input))
print output

所以list[0] -> (6, 'gold', 'dog', 'hot')

<强>输出

 [(6, 'gold', 'dog', 'hot'), (6, 'gold', 'dog', 'cold'), (6, 'gold', 'cat', 'hot'), (6, 'gold', 'cat', 'cold'), 
 (6, 'blue', 'dog', 'hot'), (6, 'blue', 'dog', 'cold'), (6, 'blue', 'cat', 'hot'), (6, 'blue', 'cat', 'cold'), 
 (4, 'gold', 'dog', 'hot'), (4, 'gold', 'dog', 'cold'), (4, 'gold', 'cat', 'hot'), (4, 'gold', 'cat', 'cold'), 
 (4, 'blue', 'dog', 'hot'), (4, 'blue', 'dog', 'cold'), (4, 'blue', 'cat', 'hot'), (4, 'blue', 'cat', 'cold')]

并非所有列表中的所有元素都是唯一的

然后使用itertools.groupby

import itertools

input = [[1, 2], [1, 2], [1, 2], [1, 2]];
output = [k for k,_ in list(itertools.groupby(itertools.product(*input)))]
print output

<强>输出

[[1, 1, 1, 1], [1, 1, 1, 2], [1, 1, 2, 2], [1, 1, 1, 2], [1, 1, 2, 2], [1, 2, 2, 2], 
[1, 1, 1, 2], [1, 1, 2, 2], [1, 2, 2, 2], [1, 1, 2, 2], [1, 2, 2, 2], [2, 2, 2, 2]]   

性能

使用数字= 1000的示例timeit

0.00650215148926 (without group by)
0.02952003479    (with group by)
0.0323181152344  (algorithm from @GarrettR)

答案 1 :(得分:0)

这样的事可能有用。认为它并不认为你有一个键列表。相反,它通过枚举列表的产品来动态生成密钥。

a,b,c,d = [6, 4, 7], ['gold', 'blue', 'red'], ['dog', 'cat', 'echidna'], ['hot', 'cold', 'rainy']
from itertools import product
forward = {}
backward = {}
for i,thing in enumerate(product(a,b,c,d)):
    forward[i] = thing
    backward[thing] = i

示例映射转发

77 -> (7, 'red', 'cat', 'rainy')
78 -> (7, 'red', 'echidna', 'hot')
79 -> (7, 'red', 'echidna', 'cold')

答案 2 :(得分:0)

您可以使用公式构建有效的映射,而无需实现数据结构。假设我们反复采用n mod每个序列的长度并除以长度。这给了我们:

def get_nth(seqs, n):
    out = []
    for seq in seqs:
        i = n % len(seq)
        n //= len(seq)
        out.append(seq[i])
    return out

之后我们

>>> seqs = [[6, 4, 7], ['gold', 'blue', 'red'],
        ['dog', 'cat', 'echidna'], ['hot', 'cold', 'rainy']]
>>> get_nth(seqs, 0)
[6, 'gold', 'dog', 'hot']
>>> get_nth(seqs, 1)
[4, 'gold', 'dog', 'hot']
>>> get_nth(seqs, 80)
[7, 'red', 'echidna', 'rainy']
>>> len(set(tuple(get_nth(seqs, i)) for i in range(81)))
81

即使在很长的名单上,这也会很快发挥作用:

>>> seqs = [list(range(10**3))]*10**3
>>> %timeit get_nth(seqs, 0)
1000 loops, best of 3: 592 µs per loop
>>> %timeit get_nth(seqs, (10**3)**(10**3)-1)
100 loops, best of 3: 11.2 ms per loop
>>> get_nth(seqs, (10**3)**(10**3)-1)[:10]
[999, 999, 999, 999, 999, 999, 999, 999, 999, 999]