附加到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@']