简体   繁体   中英

How to generate a list of all possible alphabetical combinations based on an input of numbers

I have just come across an interesting interview style type of question which I couldn't get my head around.

Basically, given a number to alphabet mapping such that [1:A, 2:B, 3:C ...] , print out all possible combinations.

For instance "123" will generate [ABC, LC, AW] since it can be separated into 12,3 and 1,23.

I'm thinking it has to be some type of recursive function where it checks with windows of size 1 and 2 and appending to a previous result if it's a valid letter mapping.

If anyone can formulate some pseudo/python code that'd be much appreciated.

As simple as a tree

Let suppose you have give "1261"

Construct a tree with it a Root .

By defining the node(left , right ) , where left is always direct map and right is combo

version suppose for the if you take given Number as 1261

1261 ->

(1(261) ,12(61)) -> 1 is left-node(direct map -> a) 12 is right node(combo-map1,2->L)

(A(261) , L(61)) ->

(A(2(61),26(1))) ,L(6(1)) ->

(A(B(6(1)),Z(1)) ,L(F(1))) ->

(A(B(F(1)),Z(A)) ,L(F(A))) ->

(A(B(F(A)),Z(A)) ,L(F(A)))

so now you have got all the leaf node..

just print all paths from root to leaf node , this gives you all possible combinations .

like in this case

ABFA , AZA , LFA

So once you are done with the construction of tree just print all paths from root to node

which is your requirement .

So I managed to hack together an answer, it's not as pythonic as I'd like and there may be some redundancies, but it works with the 123 example to output ABC,AW, and LC.

I'll probably clean it up tomorrow (or if someone wants to clean it up), just posting it in case someone is also working on it and is wondering.

def num_to_alphabet(numbers, ans = ""):
if not numbers:
    print ans
numbers = str(numbers)
window = numbers[:2]
alph = string.uppercase
ans = ans[:]
ans2 = ans[:]
window_val = ""
try:
    if window[0]:
        val = int(numbers[0])-1
        if alph[val]:
            ans += alph[val]
            num_to_alphabet(numbers[1:], ans)
    if window[1]:
        val = int(window) -1 
        if alph[val]:
            ans2 += alph[val]
            if len(window) > 1:
                num_to_alphabet(numbers[2:],ans2)
            else:
                num_to_alphabet(numbers[1:],ans2)
except IndexError:
    pass
charMap = {'1':'A', '2':'B' ... }
def getNodes(str):
    results = []
    if len(str) == 0: return results
    c = str[0]
    results.append(c)
    results = results.join(c.join(getNodes(str[1:])))
    if str[:2] in charMap.keys(): results = results.join(c.join(getNodes(str[2:])))
    return results
def mapout(nodes):
    cArray = []
    for x in nodes:
        cx = ''
        for y in x:
            cx = cx + charMap.get(y)
        cArray.append(cx)
    return cArray
res = getNodes('12345')
print(mapout(res))

Untested, but I believe this is along the lines of what you're looking for.

The following answer recursively tries all possibilities at the current position (there are more than two!) and goes on with the remainder of the string. That's it.

from string import ascii_uppercase

def alpha_combinations(s):
    if len(s) == 0:
        yield ""
        return
    for size in range(1, len(s) + 1):
        v = int(s[:size])
        if v > 26:
            break
        if v > 0:
            c = ascii_uppercase[v - 1]
            for ac in alpha_combinations(s[size:]):
                yield c + ac 

print(list(alpha_combinations(input())))

It expects a number as a string. It gives correct output for 101010 ( ['AAJ', 'AJJ', 'JAJ', 'JJJ'] ). (I think some of the other solutions don't handle zeroes correctly.)

So, I wanted to tackle this as well, since it's actually a cool problem. So here goes my solution:

If we ignore the translations to strings for now, we are essentially looking for partitions of a set . So for the input 123 we have a set {1, 2, 3} and are looking for partitions. But of those partitions, only those are interesting which maintain the original order of the input. So we are actually not talking about a set in the end (where order doesn't matter).

Anyway, I called this “ordered partition”—I don't know if there actually exists a term for it. And we can generate those ordered partitions easily using recursion:

def orderedPartitions(s):
    if len(s) == 0:
        yield []
        return
    for i in range(1, len(s)+1):
        for p in orderedPartitions(s[i:]):
            yield [s[:i]] + p

For a string input '123' , this gives us the following partions, which is exactly what we are looking for:

['1', '2', '3']
['1', '23']
['12', '3']
['123']

Now, to get back to the original problem which is asking for translations to strings, all we need to do is check each of those partitions, if they contain only valid numbers, ie 1 to 26. And if that is the case, translate those numbers and return the resulting string.

import string
def alphaCombinations(s):
    for partition in orderedPartitions(str(s)):
        # get the numbers
        p = list(map(int, partition))

        # skip invalid numbers
        if list(filter(lambda x: x < 1 or x > 26, p)):
            continue

        # yield translated string
        yield ''.join(map(lambda i: string.ascii_uppercase[i - 1], p))

And it works:

>>> list(alphaCombinations(123))
['ABC', 'AW', 'LC']
>>> list(alphaCombinations(1234))
['ABCD', 'AWD', 'LCD']
>>> list(alphaCombinations(4567))
['DEFG']

I still am not sure of the description, but this Python script first partitions the num into its 'breaks' then tries each break member as a whole as an index into its corresponding character; then converts each digit of the member into letters of a word. Both contributions are shown before showing the sum total of all conversions to letters/words for the num "123"

>>> import string
>>> mapping ={str(n):ch for n,ch in zip(range(1,27), string.ascii_uppercase)}
>>> num = '123'
>>> [[num[:i], num[i:]] for i in range(len(num)+1)]
[['', '123'], ['1', '23'], ['12', '3'], ['123', '']]
>>> breaks = set(part for part in sum(([num[:i], num[i:]] for i in range(len(num)+1)), []) if part)
>>> breaks
{'123', '12', '3', '1', '23'}
>>> as_a_whole = [mapping[p] for p in breaks if p in mapping]
>>> as_a_whole
['L', 'C', 'A', 'W']
>>> by_char = [''.join(mapping[n] for n in p) for p in breaks]
>>> by_char
['ABC', 'AB', 'C', 'A', 'BC']
>>> everything = sorted(set(as_a_whole + by_char))
>>> everything
['A', 'AB', 'ABC', 'BC', 'C', 'L', 'W']
>>> 

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM