Python генерирует диапазон чисел, которые не имеют одинаковых и уникальных цифр

я пытаюсь понять, как создать список номеров, которые не только уникальны, но и не имеют похожих цифр. Цель состоит в том, чтобы взломать образцы хэшей с помощью крипты, я знаю, что пароли уникальны, без повторяющихся цифр и до 6 цифры

Пример>

[1,2,3,4,5,6,7,8,9...120, 123,124,125,126,127... 123456,123457...]

поэтому 122 или 123451 или 12345673, потому что будут повторяющиеся числа

мой код

#!/usr/bin/env python

from os import getuid
from crypt import crypt
import time

# all initialisation here
password = range(1000000)
# all initialisation ends here

def VerifyHash(shadowHashes, salt, user):
    # crypt("Message", "Salt")
    for i in password:
        if (shadowHashes == crypt(str(i),salt)):
            print "Password of %s is " % user + str(i)
            break
        else:
            pass

def main():
    with open('shadow.txt') as p:
            for line in p:
                shadowList = line
                shadowHashes = shadowList.split(':')[1]
                user = shadowList.split(':')[0]
                salt = shadowHashes[:12]
                VerifyHash(shadowHashes,salt,user)  

main()

на данный момент я использую диапазон (1000000), и он работает, но неэффективен, потому что числа, с которыми я сравниваю, уникальны и не содержат повторяющихся цифр, поэтому я хочу сделать свою программу на Python более эффективной.

Пожалуйста, укажите мне правильное направление


person CwhatC    schedule 27.07.2016    source источник
comment
Пожалуйста, включите свой код; это поможет нам помочь вам намного лучше.   -  person Martijn Pieters    schedule 27.07.2016
comment
Мне любопытно посмотреть, как вы на самом деле проверяете повторяющиеся цифры.   -  person Mad Physicist    schedule 27.07.2016
comment
Для сравнения повторяющихся цифр используйте len(str(i)) == len(set(str(i)))   -  person joel goldstick    schedule 27.07.2016
comment
Ознакомьтесь с этим сообщением: Как сгенерировать диапазон случайных чисел в питоне без повторения   -  person Just Ice    schedule 27.07.2016
comment
@joelgoldstick Я собирался опубликовать, когда увидел, что вы уже прокомментировали что-то подобное   -  person Moses Koledoye    schedule 27.07.2016
comment
Почему-то я не вижу связи между вашим кодом и вашим вопросом...   -  person tobias_k    schedule 27.07.2016
comment
@MosesKoledoye Я видел твой пост. Оставить его. За него проголосовали и завернули тест в генератор, так что я думаю, что это хорошее решение.   -  person joel goldstick    schedule 27.07.2016


Ответы (3)


Вы можете проверить, одинакова ли длина числа, представленного в виде строки, когда цифры в числе помещены в набор:

def unique_count():
    for i in range(1000000):
        if len(str(i)) == len(set(str(i))):
            yield i

Набор устраняет повторяющиеся цифры, поэтому числа, не имеющие повторяющихся цифр, проходят условие.

person Moses Koledoye    schedule 27.07.2016
comment
Это работает, но чрезвычайно расточительно, так как будет тестироваться в 10 000 раз больше чисел, чем нужно, и в результате примерно в 3 раза медленнее генерируются первые 10 000 чисел из моего решения. , становясь все медленнее и медленнее по мере увеличения чисел. Обратите внимание, что вы можете вычислить количество цифр, а не использовать набор. Не то, чтобы это помогло избежать огромных потерь. - person Martijn Pieters; 27.07.2016
comment
(и извиняюсь, сначала я тестировал range() на Python 2, а не xrange()). - person Martijn Pieters; 27.07.2016
comment
@MartijnPieters Никаких сомнений. Спасибо за альтернативу подсчета цифр. Вы правы в том, что частота пропуска числа увеличивается с увеличением размера числа. Я не думал об этом. Бьюсь об заклад, другие пользователи, которые ищут этот вопрос, сочтут ваше решение гораздо более эффективной альтернативой. - person Moses Koledoye; 27.07.2016

Используйте itertools.permutations() для увеличения количества повторяющихся цифр, вплоть до 9, комбинируя их со всеми цифрами от 1 до 9 (чтобы предотвратить создание чисел с начальным 0).

from itertools import permutations

def generate_unique_numbers():
    yield 0
    for i in range(10):
        for leading in '123456789':
            if not i:  # 1-digit numbers
                yield int(leading)
                continue
            remaining_digits = '0123456789'.replace(leading, '')
            for combo in permutations(remaining_digits, i):
                yield int(leading + ''.join(combo))

Это генерирует все такие допустимые числа без необходимости что-либо пропускать. Таких чисел 8877691, от 0 до 9876543210:

>>> sum(1 for _ in generate_unique_numbers())
8877691
>>> next(generate_unique_numbers())
0
>>> for i in generate_unique_numbers(): pass
...
>>> i
9876543210

Несколько образцов вывода:

>>> from itertools import islice
>>> gen = generate_unique_numbers()
>>> list(islice(gen, 15))
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 12, 13, 14, 15]
>>> list(islice(gen, 150, 165))
[204, 205, 206, 207, 208, 209, 210, 213, 214, 215, 216, 217, 218, 219, 230]
>>> list(islice(gen, 100000, 100015))
[542319, 542360, 542361, 542367, 542368, 542369, 542370, 542371, 542376, 542378, 542379, 542380, 542381, 542386, 542387]
>>> list(islice(gen, 1000000, 1000015))
[31279056, 31279058, 31279064, 31279065, 31279068, 31279084, 31279085, 31279086, 31279405, 31279406, 31279408, 31279450, 31279456, 31279458, 31279460]

Этот метод значительно быстрее, чем генерация всех чисел с помощью range(9876543211), а затем отфильтровывание тех, в которых повторяются цифры (что и делает Моисей Коледой):

>>> from timeit import timeit
>>> from itertools import islice
>>> def consume_n(it, n): next(islice(it, n, n), None)
...
>>> timeit('consume_n(gen(), 10000)', 'from __main__ import consume_n, unique_count as gen', number=100)
1.825788974761963
>>> timeit('consume_n(gen(), 10000)', 'from __main__ import consume_n, generate_unique_numbers as gen', number=100)
0.6307981014251709

Приведенный выше код генерирует только первые 10000 чисел для каждого подхода и повторяет эти тесты 100 раз. Мой подход легко в 3 раза быстрее!

Увеличьте количество (и уменьшите количество повторений, чтобы оно оставалось управляемым), и контраст возрастет:

>>> timeit('consume_n(gen(), 100000)', 'from __main__ import consume_n, unique_count as gen', number=10)
4.125269889831543
>>> timeit('consume_n(gen(), 100000)', 'from __main__ import consume_n, generate_unique_numbers as gen', number=10)
0.6416079998016357

Теперь разница выросла в 6 раз быстрее. Однократное создание первого миллиона чисел занимает 23 секунды с версией range и 0,67 секунды с приведенным выше генератором:

>>> timeit('consume_n(gen(), 1000000)', 'from __main__ import consume_n, unique_count as gen', number=1)
23.268329858779907
>>> timeit('consume_n(gen(), 1000000)', 'from __main__ import consume_n, generate_unique_numbers as gen', number=1)
0.6738729476928711

И чем дальше по ряду вы идете, тем больше натуральных чисел нужно пропустить и разница в скорости только растет; например, все числа в диапазоне 8800000000-8899999999 должны быть пропущены, а подход range() будет проверять все из них. Это 100 миллионов потерянных циклов!

Генератор может выдать все возможные такие числа за 6,7 секунды на моем ноутбуке:

>>> from collections import deque
>>> def consume(it): deque(it, maxlen=0)
...
>>> timeit('consume(gen())', 'from __main__ import consume, generate_unique_numbers as gen', number=1)
6.6731719970703125

Я не осмелился проверить, сколько времени занимает подход range(); таких чисел чуть менее 9 миллионов, но подход range() проверит около 10 миллиардов возможностей, в 10 000 раз больше чисел, чем необходимо.

person Martijn Pieters    schedule 27.07.2016
comment
Спасибо за комментарий! ценю это, попробовал, но понял, что код @Moses Koledoye короче и делает то же самое! (: - person CwhatC; 27.07.2016
comment
@CwhatC: добавлены показатели производительности. Вы можете использовать подход Моисея, но это займет намного больше времени. Вы сказали, что хотели чего-то более эффективного? - person Martijn Pieters; 27.07.2016
comment
Сейчас попробую ваш метод, спасибо за отзыв! Я очень ценю помощь и постараюсь узнать как можно больше о двух подходах. - person CwhatC; 28.07.2016

Вы можете использовать приведенную ниже функцию генерации для максимального числа i, тогда она сгенерирует список цифр, меньших, чем i, уникальный и без повторения цифры.

def isDigitsRepeated(integer):
    n = str(integer)
    digits = []
    for digit in n:
        if digit in digits:
            return True
        digits += [digit]
    return False

def generate(maximum):
    lst = []
    for x in range(maximum):
        if not isDigitsRepeated(x):
            lst += [x]
    return lst
person Salah Eddine Lahniche    schedule 27.07.2016