附加到Python中,列出每个列表项的所有可能转换
我有一个可能的密码列表,我需要在此列表中附加每个密码的简单转换。说我的名单是附加到Python中,列出每个列表项的所有可能转换,python,list,Python,List,我有一个可能的密码列表,我需要在此列表中附加每个密码的简单转换。说我的名单是 ['sauce', 'banana'] 我在这里展示了一系列的转换 “a'-->'@” 's'-->'$' 然后,我想将每个可能的转换添加到列表中。所以现在列表应该是这样的 ['$auce', 's@uce', '$@uce', 'b@nana', 'ban@na', 'banan@', 'b@n@na', 'b@nan@,' 'ban@n@', 'b@n@n@'] 在Python中如何实现这一点 我首先尝试创建
['sauce', 'banana']
我在这里展示了一系列的转换
“a'-->'@”
's'-->'$'
然后,我想将每个可能的转换添加到列表中。所以现在列表应该是这样的
['$auce', 's@uce', '$@uce', 'b@nana', 'ban@na',
'banan@', 'b@n@na', 'b@nan@,' 'ban@n@', 'b@n@n@']
在Python中如何实现这一点
我首先尝试创建一个可以进行所有转换的函数。然后我得到了转换后的字符串,基本上和原始字符串做了一个叉积。然而,这会导致大量的重复,而且似乎有点骇人
职能:
def symbolize(s):
options = {
'a': '@',
'S': '$'
}
copy = ''
for i in range(len(s)):
if s[i] in options:
copy += options[s[i]]
else:
copy += s[i]
return copy
然后是叉积:
for x in range(len(candidates)):
candidates += list(''.join(t) for t in itertools.product(
*zip(candidates[x], symbolize(candidates[x]))))
如果需要,可以使用递归,尽管pytohn将其深度限制为2000: 创建映射和列表:
lst = ['sauce', 'banana']
mapping = {'a':'@', 's':'$'}
现在递归生成所有可能性(包括根本不替换):
输出:
[list(opts(mapping, st)) for st in lst]
=> [['$@uce', 's@uce', '$auce', 'sauce'], ['b@n@n@', 'ban@n@', 'b@nan@', 'banan@', 'b@n@na', 'ban@na', 'b@nana', 'banana']]
我真的很喜欢这个答案!这里有很多关于字符串的迭代,但是我喜欢我的答案
import functools
def transform(pwd, subs):
result = {pwd}
stack = [pwd]
# contains all resolved strings left to permute on
while True:
pwd = stack.pop()
# grab a password
if not stack and not any(i in subs for i in pwd):
return result
# if the stack is empty and is no way to permute further,
# then return our result.
for idx,ch in enumerate(pwd):
if ch in subs:
repl = subs[ch]
transformation = pwd[:idx]+repl+pwd[idx+1:]
# transformation is our transformed word
result.add(transformation)
# add our transformation to our result set
stack.append(transformation)
# and toss it on our stack to transform further
def transform_multiple(pwds, subs):
return functools.reduce(set.union,
(transform(pwd, subs) for pwd in pwds))
演示:
如果我要在这方面花费更多的时间,我可能会删除If not stack和not any(…)
调用,并在for idx,ch in enumerate
循环中放置一个标记,该标记用于标记该字符串是否有更改,然后在循环结束后测试If not flag and not stack:return result
。这将节省我们每次通过循环进行pwd
和len(pwd)
成员资格测试的整个迭代
from itertools import product
def all_versions_of_word(word, alt_chars, skip_orig=True):
chars = [ch + alt_chars.get(ch, "") for ch in word]
combos = product(*chars)
if skip_orig and word: next(combos) # drop the first item
return ("".join(c) for c in combos)
def transform_passwords(passwords, alt_chars={"a":"@", "s":"$"}):
for word in passwords:
yield from all_versions_of_word(word, alt_chars)
就像
>>> list(transform_passwords(['sauce', 'banana']))
['s@uce',
'$auce',
'$@uce',
'banan@',
'ban@na',
'ban@n@',
'b@nana',
'b@nan@',
'b@n@na',
'b@n@n@']
如果您正在努力开始,请尝试使用单个密码解决此问题。如果这仍然太难,就试着先解决一个字母的问题。如果你不想重复,就用集合。set([a,a])==set([a])。我认为您可以简单地使用
itertools.product
修改答案,并扔掉第一个元素(这是不可替换的情况)。变量名称前下划线的用途是什么?1。防止重写Python的内置str
。2.防止从外部上下文重写变量。我在transform\u passwords
@alexjp中的from
上得到了一个无效的语法错误:yield from
是相对较新的语法(Python 3.3+);对于Python的较低版本,您可以对word(word,alt\u chars)的所有版本中的版本执行:生成版本
。它的功能完全相同,只是有点冗长。我发现了一个bug。如果alt_字符将特定字符映射到两个不同的对象(例如,“S'->'$”和“S'->'5”),则将只使用后面在alt_字符中指定的一个。如果它能为一个字符处理多个可能的映射,那就太好了。@alexjp:试试's':'$5'
。dict不能将一个键映射到两个值,因此我将备用值打包成一个字符串。这不是一个bug,你只是用错了;-)
from itertools import product
def all_versions_of_word(word, alt_chars, skip_orig=True):
chars = [ch + alt_chars.get(ch, "") for ch in word]
combos = product(*chars)
if skip_orig and word: next(combos) # drop the first item
return ("".join(c) for c in combos)
def transform_passwords(passwords, alt_chars={"a":"@", "s":"$"}):
for word in passwords:
yield from all_versions_of_word(word, alt_chars)
>>> list(transform_passwords(['sauce', 'banana']))
['s@uce',
'$auce',
'$@uce',
'banan@',
'ban@na',
'ban@n@',
'b@nana',
'b@nan@',
'b@n@na',
'b@n@n@']