Более эффективный способ получить целые перестановки?

Я могу получить целые перестановки, например:

myInt = 123456789

l = itertools.permutations(str(myInt))
[int(''.join(x)) for x in l]

Существует ли более эффективный способ перестановки подстановок integer в Python, пропущенных накладных расходов на создание строки, а затем присоединения к сгенерированным кортежам? Сроки, процесс соединения с кортежем делает это в 3 раза больше, чем list(l).

добавлена ​​вспомогательная информация

myInt =123456789
def v1(i): #timeit gives 258ms
    l = itertools.permutations(str(i))
    return [int(''.join(x)) for x in l]

def v2(i): #timeit gives 48ms
    l = itertools.permutations(str(i))
    return list(l)

def v3(i): #timeit gives 106 ms
    l = itertools.permutations(str(i))
    return [''.join(x) for x in l]

Ответ 1

Вы можете сделать:

>>> digits = [int(x) for x in str(123)]
>>> n_digits = len(digits)
>>> n_power = n_digits - 1
>>> permutations = itertools.permutations(digits)
>>> [sum(v * (10**(n_power - i)) for i, v in enumerate(item)) for item in permutations]
[123, 132, 213, 231, 312, 321]

Это позволяет избежать преобразования в корневой каталог и из него, поскольку он будет использовать целочисленную позицию в кортеже для вычисления его значения (например, (1,2,3) означает 100 + 20 + 3).

Поскольку значение n_digits известно и одинаково в течение всего процесса, я думаю, вы также можете оптимизировать вычисления для:

>>> values = [v * (10**(n_power - i)) for i, v in enumerate(itertools.repeat(1, n_digits))]
>>> values
[100, 10, 1]
>>> [sum(v * index for v, index in zip(item, values)) for item in permutations]
[123, 132, 213, 231, 312, 321]

Я также думаю, что нам не нужно все время вызывать zip(), потому что нам не нужен этот список:

>>> positions = list(xrange(n_digits))
>>> [sum(item[x] * values[x] for x in positions) for item in permutations]
[123, 132, 213, 231, 312, 321]

Ответ 2

Это даст вам generator:

import itertools as it
gen = it.permutations(range(1, 10))

Затем вы можете перебирать каждый элемент:

for i in gen:
    #some code

Или преобразуйте его в список, но потребуется некоторое время:

items = list(gen)

EDIT: Уточнено, что вы хотите вернуть целое число, возможно, самый быстрый способ - использовать другую ленивую оценку:

gen = (int('%d%d%d%d%d%d%d%d%d' % x) for x in it.permutations(range(1, 10)))

Ответ 3

Я не могу комментировать ответ Симеона, поэтому я добавляю это здесь.

Если вы попытаетесь переставить 120 с функцией в ответе, вы получите

[120,102,210,201,12,21]

12 и 21 неправильные ответы, поэтому я сделал модификацию, чтобы отбросить их:

def permute(n):
        digits = [int(x) for x in str(n)]
        n_digits = len(digits)
        n_power = n_digits - 1
        values = [v * (10**(n_power - i)) for i, v in
            enumerate(itertools.repeat(1, n_digits))]
        positions = list(range(n_digits))
        permutations = {sum(item[x] * values[x] for x in positions) for
            item in itertools.permutations(digits) if item[0] > 0}
        for p in permutations:
            yield p

Редактировать: также забыл добавить, что функция будет считать одинаковые цифры дважды, оставляя вас с дубликатами, поэтому я также изменил это.