如何从此表构建所有可能元组的列表?

时间:2009-06-17 15:12:01

标签: python algorithm

假设我有一组列定义:

Col1: value11 value12 value13
Col2: value21 value22 
Col3: value31 value32 value33
...

给定列的一些子集--2或更多 - 我想找到这些列的所有可能值。假设我选择上面的第1列和第2列:

(value11 value21)
(value11 value22)
(value12 value21)
(value12 value22)
(value13 value21)
(value13 value22)

如果我选择2:3:

(value21 value31)
(value21 value32)
(value21 value33)
(value22 value31)
(value22 value32)
(value22 value33)

如果我选择了全部三个:

(value11 value21 value31)
(value11 value21 value32)
...

我在python中实现了这个,我想要一个 fast 算法来做到这一点。我的输入是一个元组列表:(columnName,columnValueList)

有什么建议吗?

6 个答案:

答案 0 :(得分:15)

获得此功能的最佳方法是使用itertools.product()。例如:

import itertools

group1 = ['a', 'b']
group2 = ['c', 'd']

print list(itertools.product(group1, group2))

#==> [('a', 'c'), ('a', 'd'), ('b', 'c'), ('b', 'd')]

此函数接受多个参数(即多列)。

有关iterools.product()的更多帮助,请参阅this

答案 1 :(得分:2)

杰里米的更一般的解决方案:

import itertools
full = [[value11, value12, value13],
        [value21, value22],
        [value31, value32, value33]]
ids = 0, 2

或者如果它是dict(应该是):

full = {'col1': [value11, value12, value13],
        'col2': [value21, value22],
        'col3': [value31, value32, value33]}
ids = 'col1', 'col3'
selected = (full[i] for i in ids)
list(itertools.product(*selected))

答案 2 :(得分:1)

除了像jeremy建议的那样使用itertools.product()之外,您可能还需要考虑将元组列表转换为dict以快速查找columnName:

dict(tupleList)

答案 3 :(得分:1)

我敢打赌基于itertools的解决方案会更快,但如果需要避免(例如,在没有itertools.product等的情况下停留在Python 2.5上),它当然可以完全编码必须使用“基础Python”。

试图“拉出所有停留”以获得速度,可能是这样的:

def odo(*names_and_valuelists):
    aux = [[vl, 0] for n, vl in names_and_valuelists]
    if any(len(vl)==0 for vl, _ in aux):
        return
    while True:
        yield tuple(vl[i] for vl, i in aux)
        for vlandi in reversed(aux):
          if vlandi[1] == len(vlandi[0])-1:
            vlandi[1] = 0
          else:
            vlandi[1] += 1
            break
        else:
          return

虽然微小的调整可能仍会加速它(需要使用真实的样本数据进行彻底的分析!)。

以下是您的使用示例:

def main():
    data = [
        ('Col1', 'value11 value12 value13'.split()),
        ('Col2', 'value21 value22'.split()),
        ('Col3', 'value31 value32 value33'.split()),
    ]
    for tup in odo(data[0], data[1]): print tup
    print
    for tup in odo(data[1], data[2]): print tup
    print
    for i, tup in enumerate(odo(*data)):
        print tup
        if i>5: break

if __name__ == '__main__':
    main()

发出结果:

('value11', 'value21')
('value11', 'value22')
('value12', 'value21')
('value12', 'value22')
('value13', 'value21')
('value13', 'value22')

('value21', 'value31')
('value21', 'value32')
('value21', 'value33')
('value22', 'value31')
('value22', 'value32')
('value22', 'value33')

('value11', 'value21', 'value31')
('value11', 'value21', 'value32')
('value11', 'value21', 'value33')
('value11', 'value22', 'value31')
('value11', 'value22', 'value32')
('value11', 'value22', 'value33')
('value12', 'value21', 'value31')

答案 4 :(得分:0)

看起来itertools.combination可以帮到你。

>>> from itertools import combinations
>>> list(combinations(xrange(5), 2))
[(0, 1), (0, 2), (0, 3), (0, 4), (1, 2), (1, 3), (1, 4), (2, 3), (2, 4), (3, 4)]
>>> list(combinations(xrange(5), 3))
[(0, 1, 2), (0, 1, 3), (0, 1, 4), (0, 2, 3), (0, 2, 4), (0, 3, 4), (1, 2, 3), (1, 2, 4),   (1, 3, 4), (2, 3, 4)]

答案 5 :(得分:0)

使用合并创建交叉连接。见 (https://www.geeksforgeeks.org/python-program-to-perform-cross-join-in-pandas/)

data={'Col1': ['value11', 'value12', 'value13'],
'Col2': ['value21', 'value22','value23'] ,
'Col3': ['value31', 'value32', 'value33']
}
df=pd.DataFrame(data)
df.reset_index(inplace=True)
print(df)

col1=pd.DataFrame(df['Col1'])
col2=pd.DataFrame(df['Col2'])
col3=pd.DataFrame(df['Col3'])

col1['key'] = 1
col2['key'] = 1
col3['key'] = 1

col1=pd.merge(col1, col2, on ='key')
col1=pd.merge(col1, col3, on ='key').drop("key", 1)