找到第n个组合(增量方法)的字母(列表)

时间:2013-12-07 19:37:11

标签: python combinations permutation dynamic-programming

在给出字母表列表的情况下,找到第n个组合的Pythonic方法是什么?

# a = list("abc")

预期输出(比赛):

# a, b, c, aa, ab, ac, ba, bb, bc, ca, cb, cc, aaa, aab, aac, and so on... (until the nth)

4 个答案:

答案 0 :(得分:4)

使用itertools,生成沿线的所有组合:

def powerprod(iterable):
    s = list(iterable)
    for r in itertools.count(1):
        for c in itertools.product(s, repeat=r):
            yield c

演示:

>>> map(''.join, itertools.islice(powerprod('eht'), 34))
['e', 'h', 't', 'ee', 'eh', 'et', 'he', 'hh', 'ht', 'te', 'th', 'tt', 'eee', 'eeh', 'eet', 'ehe', 'ehh', 'eht', 'ete', 'eth', 'ett', 'hee', 'heh', 'het', 'hhe', 'hhh', 'hht', 'hte', 'hth', 'htt', 'tee', 'teh', 'tet', 'the']

<强>更新

AFAIK,@ gibbler方法不起作用,因为不区分0011以及类似的组合。这是获得第n个组合的更快方法:

from itertools import product, islice

def max_sum_n_pow_lower_x(x, n):
    """ returns tuple of number of summand and maximal sum
        of form `n` + `n`**2 + `n`**3  not greater than `x` """
    i, c, s = 1, 0, 0
    while s < x:
       i *= n
       c += 1
       s += i
    return c-1, s-i

def get_nth_pow(iterable, n):
    l = list(iterable)
    repeat, start_from = max_sum_n_pow_lower_x(n, len(l))
    prod = itertools.product(l, repeat=repeat+1)
    return ''.join(list(islice(prod, n-start_from))[-1])

演示:

>>> get_nth_pow('eht', 34)
'the'

答案 1 :(得分:3)

您的示例是base3号码。

n转换为base3(或字母表的长度)。然后将“数字”替换为 字母表中的符号。

这允许您在不生成所有先前的n-1个条目的情况下找到第n个值

答案 2 :(得分:1)

import itertools

def gen_combinations(alphabet):
  n = 1
  while True:
    for item in itertools.combinations_with_replacement(alphabet, n):
      yield ''.join(item)
    n += 1

print list(itertools.islice(gen_combinations("abc"), 20))

(这需要Python 2.7,但可以很容易地为早期版本的itertools重写。)

答案 3 :(得分:1)

由于user2357112对gnibbler的回答发表了评论,您想要使用的是bijective number system,其中字母表中的字符是数字。

以下是您在代码中执行此操作的方法:

import math

def get_bijective_val(n, alphabet):
    base = len(alphabet)
    digits = []
    while n:
        remainder = math.ceil(n/base)-1
        digits.append(n - remainder*base)
        n = remainder
    digits.reverse()
    return "".join(alphabet[digit-1] for digit in digits)

即使对于非常大的数字或长字母,这也应该有效。它的运行时间与输出字符串的长度成正比,或者基数中整数的log等于字母表的长度。

以下是一个示例运行:

>>> for i in range(40):
    print(i, get_bijective_val(i, "eht"))


0 
1 e
2 h
3 t
4 ee
5 eh
6 et
7 he
8 hh
9 ht
10 te
11 th
12 tt
13 eee
14 eeh
15 eet
16 ehe
17 ehh
18 eht
19 ete
20 eth
21 ett
22 hee
23 heh
24 het
25 hhe
26 hhh
27 hht
28 hte
29 hth
30 htt
31 tee
32 teh
33 tet
34 the
35 thh
36 tht
37 tte
38 tth
39 ttt