我有一个列表列表,我想在不使用任何元素的情况下复制itertools.product()
的效果。
>>> list = [['A', 'B'], ['C', 'D'], ['A', 'B']]
>>> [''.join(e) for e in itertools.product(*list)]
['ACA', 'ACB', 'ADA', 'ADB', 'BCA', 'BCB', 'BDA', 'BDB']
>>> # Desired output: ['ACB', 'ADB', 'BCA', 'BDA']
我需要使用它的列表太大而无法计算itertools.product
并删除不需要的元素。 (来自itertools.product
的250亿个排列,而我想要的输出只有~500,000)。优选地,答案是可迭代的。
编辑:我知道"产品"对于我需要的是错误的术语,但我很难找到我正在寻找的词。
Edit2:这是我希望执行此操作的列表:
[['A', 'H', 'L'], ['X', 'B', 'I'], ['Q', 'C', 'V'], ['D', 'N'], ['E', 'F'], ['E', 'F'], ['G'], ['A', 'H', 'L'], ['X', 'B', 'I'], ['W', 'U', 'J', 'K', 'M'], ['W', 'U', 'J', 'K', 'M'], ['A', 'H', 'L'], ['W', 'U', 'J', 'K', 'M'], ['D', 'N'], ['P', 'O', 'T'], ['P', 'O', 'T'], ['Q', 'C', 'V'], ['R'], ['S'], ['P', 'O', 'T'], ['W', 'U', 'J', 'K', 'M'], ['Q', 'C', 'V'], ['W', 'U', 'J', 'K', 'M'], ['X', 'B', 'I']]
答案 0 :(得分:2)
import React from 'react';
import './App.css';
var createReactClass = require('create-react-class');
var GameBoard = createReactClass({
getInitialState() {
return {
gameState: 0,
heroLoc: 0,
enemyLoc: 0,
enemyType : 0,
}
},
gameStart() {
this.setState({
gameState: 1
})
this.createEnemy();
},
changeEnemyType(){
var type = Math.floor(Math.random()*3);
var loc = Math.round(Math.random());
this.setState({enemyLoc : loc});
this.setState({enemyType : type});
},
createEnemy(){
setInterval(this.changeEnemyType, 1000);
},
render() {
var state = this.state
var enemyCls = state.gameState? ("enemy enemy"+ state.enemyType + " loc" + state.enemyLoc):"enemy";
return (
<div className = "board" >
<div className="road">
<div className={enemyCls} id="enemy"></div>
</div>
<span className = { state.gameState? "start hide":"start" } onClick = { this.gameStart }> Start </span>
</div>
)
}
});
较长的输入需要大约五秒钟才能在我的机器上运行。我使用test1 = [['A', 'B'], ['C', 'D'], ['A', 'B']]
test2 = [['A', 'H', 'L'], ['X', 'B', 'I'], ['Q', 'C', 'V'], ['D', 'N'], ['E', 'F'], ['E', 'F'], ['G'], ['A', 'H', 'L'],
['X', 'B', 'I'], ['W', 'U', 'J', 'K', 'M'], ['W', 'U', 'J', 'K', 'M'], ['A', 'H', 'L'],
['W', 'U', 'J', 'K', 'M'], ['D', 'N'], ['P', 'O', 'T'], ['P', 'O', 'T'], ['Q', 'C', 'V'], ['R'], ['S'],
['P', 'O', 'T'], ['W', 'U', 'J', 'K', 'M'], ['Q', 'C', 'V'], ['W', 'U', 'J', 'K', 'M'], ['X', 'B', 'I']]
def prod(curr, *others):
if not others:
for x in curr:
yield {x} # (x,) for tuples
else:
for o in prod(*others):
for c in curr:
if c not in o:
yield {c, *o} # (c, *o) for tuples
print([''.join(x) for x in prod(*test1)])
# ['ABC', 'ABD', 'ABC', 'ABD']
print(sum(1 for x in prod(*test2)))
# 622080
来传递值,因为它们在成员资格检查方面比元组或列表更有效。如果有必要,你可以使用元组,它会慢一些。
要考虑的一些问题:订单有关系吗?当我们无法使用当前列表中的项目时(因为它们都已被使用过),您希望发生什么?
答案 1 :(得分:2)
一个简单的基于堆栈的实现:
def product1(l): return product1_(l,0,[])
def product1_(l,i,buf):
if i==len(l): yield buf
else:
for x in l[i]:
if x not in buf:
buf.append(x)
yield from product1_(l,i+1,buf)
buf.pop()
这比Patrick Haugh的回答慢一点(我的测试用例得到了18秒),但它以可预测的顺序给出了结果。
请注意,您必须在生成“他们”时处理这些值,因为它们都是相同的列表buf
;您可以写yield tuple(buf)
或yield "".join(buf)
来生成单独的“熟”值(成本不到一秒)。
如果值是字母,您可以使用“位掩码”列表来实现冲突测试,这会将时间缩短到大约13秒(但使用set
的速度也一样快)。其他可能的优化包括首先处理具有较少合格元素的列表,以减少回溯;这可以将这种情况降低到11秒。
答案 2 :(得分:1)
您的具体案件有一个有趣的属性。如果我们将它安排在一个计数器中,我们会看到每个列表的出现次数与其条目相同:
Counter({('A', 'H', 'L'): 3,
('D', 'N'): 2,
('E', 'F'): 2,
('G',): 1,
('P', 'O', 'T'): 3,
('Q', 'C', 'V'): 3,
('R',): 1,
('S',): 1,
('W', 'U', 'J', 'K', 'M'): 5,
('X', 'B', 'I'): 3})
换句话说,忽略顺序,您想要的序列是列表排列的笛卡尔积。假设您的列表名为l
。然后我们可以汇总一份列表,列出子列表的所有排列并获取它们的产品:
c = set(tuple(i) for i in l)
permutations = [list(itertools.permutations(i)) for i in c]
permutation_products = itertools.products(*permutations)
permutation_products
的元素看起来像:
(('W', 'U', 'J', 'K', 'M'),
('E', 'F'),
('X', 'B', 'I'),
('Q', 'C', 'V'),
('P', 'O', 'T'),
('D', 'N'),
('G',),
('S',),
('R',),
('A', 'L', 'H'))
我们必须让它恢复正确的顺序。假设我们的排列被称为perm
。对于列表的每个子列表,我们必须找到perm
的正确元素,然后在排列中取下一个字母。我们可以通过制作字典来实现这一目标:
perm_dict = {frozenset(p): list(p) for p in perm}
然后,为了构建单个排列,我们有:
s = "".join([perm_dict[frozenset(i)].pop() for i in l])
我们可以将所有这些组合成一个生成器:
def permute_list(l):
c = set(tuple(i) for i in l)
permutations = [list(itertools.permutations(i)) for i in c]
permutation_products = itertools.product(*permutations)
for perm in permutation_products:
perm_dict = {frozenset(p): list(p) for p in perm}
yield "".join([perm_dict[frozenset(i)].pop() for i in l])