我有以下代码:
possible_keys = map(lambda combo: ''.join(combo), itertools.product(LETTERS, repeat=key_len))
它根据我传递的密钥长度生成字母表中的所有可能组合。例如,如果我传入2,它将生成aa,ab,ac等。如果我传入3,它将生成aaa,aab,aac等等。
我想通过删除字符串是完全相同字母的实例来优化我的代码,例如aaa,bbbb,ccccccc。基本上,如果这是一个矩阵,删除对角线。我怎么能用这个或者有更好的方法来实现呢?
编辑:我正在通过字典攻击来处理Vigenere Cipher。我不想透露我正在处理的大问题,因为我担心人们会给出答案而不是哈哈。虽然,现在欢迎任何建议:)这是我的程序的第一次迭代,所以它真的很低效,因为我正在浏览所有可能的键并将其与提供的字典中的内容相匹配..
答案 0 :(得分:3)
使用相同元素的运行位于
的事实→ 0 + L 1 + ... + L L-1 =(L → - 1)/(L-1)
除了元素之外,总共有L
个元素,我们可以将它们从最后的product
中排除,而不会妨碍内部循环或计算哈希值:
LETTERS='abc'
l = len(LETTERS)
p = [''.join(i) for i in itertools.product(LETTERS,repeat=l)]
step=(l**l-1)/(l-1)
for i in range(l):
del p[i*step-i] #allow for the fact that each time we delete an element,
#all indices shift backward by one
比较表现:
In [88]: letters=string.ascii_lowercase[:8] # 8**8=16777216 elements in product
In [89]: timeit ex(letters) # this solution
1 loop, best of 3: 6.1 s per loop
In [90]: timeit minus_set(letters) # subtracting a set at the end
1 loop, best of 3: 28.1 s per loop
In [92]: timeit ck_len(letters) # checking len(set(i))
1 loop, best of 3: 15.1 s per loop
In [94]: timeit not_set(letters) # checking `not in exclude'
1 loop, best of 3: 7.54 s per loop
def ex_mod_iter(letters): # counter in the loop like it'd be done in C
l = len(letters)
step=(l**l-1)/(l-1)
p = [''.join(v) for i,v in enumerate(itertools.product(letters,repeat=l)) if i % step]
return p
In [5]: timeit ex_mod_iter(letters)
1 loop, best of 3: 6.61 s per loop
答案 1 :(得分:2)
您只需检查第一个字母是否占据整个字符串,并排除符合条件的字符串:
possible_keys = [''.join(x) for x in product(L, repeat=key_len)
if len(x) != x.count(x[0])]
虽然tuple.count
具有与set()
相同的O(n)复杂度,但计数相对更便宜,因此可能比构建元组中的 <快> 。< / p>
答案 2 :(得分:1)
使用set(只能保存唯一值),我们可以这样做:
import itertools
possible_keys = [''.join(i) for i in itertools.product('AB', repeat=2) if len(set(i)) !=1]
print(possible_keys)
返回:
['AB', 'BA']
旁注:这里不需要lambda
提高速度: 如果速度更重要,我们也可以先制作一个例外列表。
exclude = {(x,)*3 for x in 'ABC'}
possible_keys= [''.join(i) for i in itertools.product('ABC', repeat=3) if i not in exclude]
对于[A-Z],您可以使用:
import string
n = 4
letters = string.ascii_uppercase
exc = {(x,)*n for x in letters}
l = [''.join(i) for i in itertools.product(letters, repeat=n) if i not in exc]
<强>定时强>
%timeit l = {(x,)*3 for x in 'ABC'};[''.join(i) for i in itertools.product('ABC', repeat=3) if i not in l ]
%timeit [''.join(i) for i in itertools.product('ABC', repeat=3) if len(set(i)) !=1]
%timeit [''.join(x) for x in itertools.product('ABC', repeat=3) if len(x) != x.count(x[0])]
100000 loops, best of 3: 5.48 µs per loop
100000 loops, best of 3: 10.7 µs per loop
100000 loops, best of 3: 8.19 µs per loop
答案 3 :(得分:0)
不确定这是多么有效,但它应该可以解决问题。
# Remove combos that are composed of the same letter.
possible_keys = map(lambda combo: ''.join(combo) if len(set(combo)) > 1 else False, itertools.product(LETTERS, repeat=key_len))
它也使用set
但在lambda表达式中进行过滤。
答案 4 :(得分:0)
您可以使用itertools.repeat获取您希望从原始列表中删除的序列列表。
import itertools
import string
# get all sequences with all same letters
all_same_sequences = [''.join(list(itertools.repeat(char, key_len))) for char in string.ascii_lowercase]
# take those sequences out of the original list
possible_keys = sort(list(set(possible_keys ) - set(all_same_sequences)))