【问题标题】:'leet' program - getting all permutations'leet' 程序 - 获取所有排列
【发布时间】:2015-05-22 22:54:07
【问题描述】:

我编写了一个简单的函数,可以将单词中的字母转换为对应的“leet”数字。

def Leet(word):
    letters = list(word.lower())
    for n, letter, in enumerate(letters):
        if letter == 'o':
            letters[n]= '0'
        elif letter == 'i':
            letters[n]= '1'
        elif letter == 'z':
            letters[n]= '2'
        elif letter == 'e':
            letters[n]= '3'
        elif letter == 'a':
            letters[n]= '4'
        elif letter == 's':
            letters[n]= '5'
        elif letter == 'g':
            letters[n]= '6'
        elif letter == 't':
            letters[n]= '7'
        elif letter == 'b':
            letters[n]= '8'
    return ''.join(letters)

所以当我输入'zit' 时,程序将返回'217'

我的问题是,如何更改它以提供所有可能的排列('217''2it''z1t''zi7''21t' 等)?我已经阅读了有关 itertools 的信息,但对于如何将其应用于我的函数感到困惑。

【问题讨论】:

  • 请注意,字典 {'o': '0', ...} 会使这很多更整洁。

标签: python permutation itertools cartesian-product


【解决方案1】:

第一个观察结果是您可以缩短查找时间,如下所示:

REPLACE = { letter: str(index) for index, letter in enumerate('oizeasgtb') }

def Leet2(word):
    letters = [ REPLACE.get(l, l) for l in word.lower() ]
    return ''.join(letters)

REPLACE 看起来像:

{'a': '4', 'b': '8', 'e': '3', 'g': '6', 'i': '1', 
 'o': '0', 's': '5', 't': '7', 'z': '2'}

REPLACE.get(l,l) 会返回替换字母,如果没有替换则返回原始字母。

第二个观察结果是您并不真正想要排列,排列是顺序的变化。 '217'的排列是:

>>> [ ''.join(p) for p in permutations('217') ]
['217', '271', '127', '172', '721', '712']

您真正需要的是对给定字符位置的所有可能选择进行编码的列表的乘积:

[('z', '2'), ('i', '1'), ('t', '7')]

如果我还显示一个可能性列表,其中包含一些没有有效替换的字符,那么它的工作原理可能会更清楚。以'red' 为例:

[('r',), ('e', '3'), ('d',)]

现在我们需要这些选项的字符串连接产品。把它们放在一起:

from itertools import product

def Leet2Combos(word):
    possibles = []
    for l in word.lower():
        ll = REPLACE.get(l, l)
        possibles.append( (l,) if ll == l else (l, ll) )
    return [ ''.join(t) for t in product(*possibles) ]

print Leet2Combos('zit')
print Leet2Combos('red')

给予:

['zit', 'zi7', 'z1t', 'z17', '2it', '2i7', '21t', '217']
['red', 'r3d']

【讨论】:

    【解决方案2】:

    使用itertools.product。另外,我建议使用dict 进行映射,而不是级联if/elif

    >>> from itertools import product
    >>> LEET = { 'z': '2', 'i': '1', 't': '7' } # and all the others     
    >>> word = "zit"
    >>> [''.join(letters) for letters in product(*({c, LEET.get(c, c)} for c in word))]
    ['zit', 'zi7', 'z1t', 'z17', '2it', '2i7', '21t', '217']
    

    请注意,LEET.get(c, c) 将从 dict 中获取“leet”字母,或使用原始字母作为默认值。 {...} 用于制作这些对集,因此没有替换的字母没有重复。在旧版本的 Python 中,您可能必须改用 set([...])

    相当复杂的product(*...) 行大致如下:

        product(*({c, LEET.get(c, c)} for c in 'zit'))
    ==> product(*({'z', LEET.get('z', 'z')}, {'i', LEET.get('i', 'i')}, {'t', LEET.get('t', 't')}))
    ==> product(*({'z', '2'}, {'i', '1'}, {'t', '7'}))
    ==> product(  {'z', '2'}, {'i', '1'}, {'t', '7'} )
    

    产生所有这些字母及其替换的cartesian product

    【讨论】:

    • 不错的答案。我想知道product(*[(... 中的* 是什么?我对 Python 还不是 100% 满意。
    • 这适用于像'zit' 这样的单词,每个字母位置都有两种选择。对于像'red' 这样的词,它的效果稍差一些,它会返回['red', 'red', 'r3d', 'r3d', 'red', 'red', 'r3d', 'r3d']——一个带有重复项的列表。建议使用set() 操作包装结果或内部列表元组以进行补偿。
    【解决方案3】:

    一种方法是使用itertools.product,正如您所提到的,它将执行列表的笛卡尔积。

    问题是要有这个列表,每个组合,例如对于 zit,列表应该是:

    [['z', '2'], ['i', '1'], ['t', '7']]
    

    我的代码:

    import itertools
    
    def leet(word):
        leet_matches = [['a', '4'],
        ['b' ,'8'],
        ['c'],
        ['d'],
        ['e', '3'],
        ['f'],
        ['g', '6'],
        ['h'],
        ['i', '1'],
        ['j'],
        ['k'],
        ['l'],
        ['m'],
        ['n'],
        ['o', '0'],
        ['p'],
        ['q'],
        ['r'],
        ['s', '5'],
        ['t', '7'],
        ['u'],
        ['v'],
        ['w'],
        ['x'],
        ['y'],
        ['z', '2']]
        l = []
        for letter in word:
            for match in leet_matches:
                if match[0] == letter:
                    l.append(match)
        return list(itertools.product(*l))
    
    print leet("zit")
    

    请注意,使用列表(或元组)列表而不是 Dict 允许您对一个字母进行多个替换,例如"i" 可以变成 "1" 或 "!"

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-05-03
      • 2012-04-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多