Как удалить номера из списка, содержащего повторяющиеся цифры?

#python #list #algorithm

Вопрос:

Я пытаюсь решить следующую проблему:

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

[123456, 889756, 854123, 997886, 634178]

Моя цель состоит в том, чтобы удалить числа с повторяющимися цифрами или получить новый список с номерами, содержащими только отдельные цифры:

[123456, 854123, 634178]

Есть ли хороший способ, как это сделать? Заранее большое вам спасибо!

Комментарии:

1. Простой способ (но, возможно, не «приятный») — преобразовать число в строку, а это-в набор символов. Если набор и строка имеют одинаковый «len», в них нет повторяющихся цифр. Вы должны применить этот тест к каждому элементу списка в цикле или к пониманию списка.

2. Ответ с этой точной техникой был опубликован 2 минуты назад…

3. @VexenCrabtree Приложение для Android с переполнением стека имеет некоторую задержку обновления.

Ответ №1:

Вы можете использовать set строковое представление числа, чтобы увидеть, сколько цифр входит в набор. Если это то же количество цифр, что и у исходного номера, он проходит тест:

 lst = [123456, 889756, 854123, 997886, 634178]
result = [n for n in lst if len(set(str(n))) == len(str(n))]

print(result)
 

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

 result = [n for n in lst if len(set(s := str(n))) == len(s)]
 

Комментарии:

1. Разве Python не великолепен в таких вещах 🙂

2. Протестировал этот код в своей задаче, и он работал идеально! Большое вам спасибо за вашу помощь!

3. @Vexen, правда, str вызывается дважды, но я не вижу, как вы можете избежать повторного вызова len , не возвращаясь к более дорогой логике. Я думаю, что накладные расходы на двойной вызов str незначительны, если номера находятся в разумном диапазоне, и добавление временной переменной, чтобы как-то избежать этого, также обходится дорого. Придется вызывать традиционный for цикл append , что медленнее, чем понимание списка. Я не думаю, что это превзойдет понимание списка, несмотря на двойной str вызов.

4. Может := быть, оператор поможет здесь: result = [n for n in lst if len(set(s := str(n))) == len(s)]

5. @AndrejKesely, может быть… Для сравнительного анализа.

Ответ №2:

Другое решение, с re :

 import re

r = re.compile(r"(d).*1")
lst = [123456, 889756, 854123, 997886, 634178]

lst = [i for i in lst if not r.search(str(i))]
print(lst)
 

С принтами:

 [123456, 854123, 634178]
 

ИЗМЕНИТЬ: Небольшой контрольный показатель:

 from timeit import timeit


lst = [123456, 889756, 854123, 997886, 634178] * 10000


def re_method(lst):
    r = re.compile(r"(d).*1")
    return [i for i in lst if not r.search(str(i))]


def trincot1(lst):
    return [n for n in lst if len(set(str(n))) == len(str(n))]


def trincot2(lst):
    return [n for n in lst if len(set(s := str(n))) == len(s)]


def afaalgo(lst):
    answer = []
    for value in lst:
        value = str(value)
        new_list = []
        for nums in value:
            new_list.append(nums)
        if sorted(list(set(new_list))) == sorted(new_list):
            answer.append(int(value))
    return answer


t1 = timeit(lambda: re_method(lst), number=10)
t2 = timeit(lambda: trincot1(lst), number=10)
t3 = timeit(lambda: trincot2(lst), number=10)
t4 = timeit(lambda: afaalgo(lst), number=10)

print(t1)
print(t2)
print(t3)
print(t4)
 

Отпечатки на моей машине (3700x/Python 3.8.5):

 0.2806989410019014
0.33745980000821874
0.263871792005375
0.8039937680005096
 

Так что версия с set() и := в данном случае самая быстрая.

Комментарии:

1. Большое вам спасибо за прекрасную идею!

2. Я добавил ответ, используя ваш тест, но в PyPy.

Ответ №3:

Вот какой-то псевдокод (не на Python):

 newList <- []
for each number in oldList
  if hasNoRepeatDigits(number)
    newList.add(number)
  endif
endfor
 

Комментарии:

1. Большое вам спасибо за вашу помощь!

Ответ №4:

 lst = [123456, 889756, 854123, 997886, 634178]

answer = []
for value in lst:
    value = str(value)
    new_list = []
    for nums in value:
        new_list.append(nums)
    if sorted(list(set(new_list))) == sorted(new_list):
        answer.append(int(value))
print(answer)
 

Комментарии:

1. Большое вам спасибо за вашу помощь!

Ответ №5:

При использовании PyPy это кажется примерно в 2-7 раз быстрее, чем у других:

 def has_duplicates(n):
  s = 0
  while n:
    d = n % 10
    if (1<<d) amp; s:
      return True
    s |= 1<<d
    n = n // 10
  return False
 
def f(lst):
  return [i for i in lst if not has_duplicates(i)]
 

Комментарии:

1. Спасибо за версию PyPy и тест! 1