#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