Упростить код без использования условий и циклов
def is_valid_pin_codes(pin_codes):
verification = set(pin_codes)
if len(verification) == len(pin_codes):
for i in verification:
try:
if len(i) != 4:
return False
else:
if i.isdigit():
break
except TypeError:
return False
else:
return False
return True
pin_codes = ['1101', '9034', '00112', '001a', '1101']
is_valid_pin_codes(pin_codes)
Передаём в функцию список из пин-кодов. Возвращаем True если пин-коды в виде строки, не больше и не меньше 4 элементов, не повторяются и хранят в себе только цифры. Если хотя бы 1 условие не выполняется - возвращаем False. Хочу для себя знать альтернативные варианты, чтобы все работало быстрее, или, может, узнать новые методы для себя, которые мог бы использовать здесь.
Ответы (3 шт):
С точки зрения читаемость-количество строк такой вариант оптимальный:
def is_valid_pin_codes(pin_codes):
if len(set(pin_codes)) != len(pin_codes):
return False
correct_pin_codes = [code for code in pin_codes
if type(code) is str
and len(code) == 4
and code.isdigit()]
return len(correct_pin_codes) == len(pin_codes)
pin_codes = ['1101', '9034', '00112', '001']
print(is_valid_pin_codes(pin_codes)) # False
pin_codes = ['1101', '9034', '0112', '0041']
print(is_valid_pin_codes(pin_codes)) # True
Дополнительно
Но при желании все можно записать и в одну строку:
def is_valid_pin_codes(pin_codes):
return len(set(pin_codes)) == len(pin_codes) and len([code for code in pin_codes if type(code) is str and len(code) == 4 and code.isdigit()]) == len(pin_codes)
Также я рекомендую почитать вам про list comprehenshions, это пригодится в дальнейшем для решения подобных (и не только) задач.
Можно использовать регулярные выражения для проверки. Возможно в данной задаче это и оверинжениринг, но если проверка будет чуть сложнее, то возможно регулярные выражения окажутся хорошим вариантом.
import re
def is_valid_pin_codes(pin_codes):
r = re.compile("^[0-9]{4}$")
filtered = list(filter(r.match, pin_codes))
return len(pin_codes) == len(filtered)
pin_codes = ['1101', '9034', '00112', '001']
print(is_valid_pin_codes(pin_codes)) # False
pin_codes = ['1101', '9034', '0112', '0041']
print(is_valid_pin_codes(pin_codes)) # True
Здесь задаем регулярное выражение, что строка может состоять только из 4 цифр. А дальше с помощью функции filter проверяем каждый элемент входного массива. Если после фильтра осталось столько же элементов, сколько и до, то значит все элементы прошли проверку.
Можно очень сильно код сократить, если библиотекой pandas воспользоваться.
Да, это съест дополнительную память на подгрузку библиотеки, зато код получается очень компактный и чудесный.
без использования условий и циклов
А ещё полностью убирает условия и циклы.
import pandas as pd
def is_valid_pin_codes(pin_codes):
s = pd.Series(pin_codes)
return all([~any(s.duplicated()),
all(s.str.isnumeric()),
all(s.str.len()==4)])
pin_codes = ['1101', '9034', '00112', '0014', '1201']
print(is_valid_pin_codes(pin_codes)) # False
pin_codes = ['1101', '9034', '1456', '6587', '1201']
print(is_valid_pin_codes(pin_codes)) # True
Как работает:
s = pd.Series(pin_codes)
Приводим список к классуSeries, который содержит полезные и необходимые нам методы- В
returnодной строкой делаем валидацию:~any(s.duplicated())s.duplicated()
Выводит массив из True / False, где значение True будет для повторяющегося элеманта. Первый элемент останется False. Т.е. для pin_codes из примера
[i for i in s.duplicated()]
выдаст
[False, False, False, False, True]- оборачиваем в
any(), получаем True, т.е. хотя бы один дубликат есть ~переворачивает значение
Т.е. если есть хотя бы один дубликат возвращаем False — проверка не пройдена
all(s.str.isnumeric())
Проверяем, что все значения не содержат букв.all(s.str.len() == 4)
По аналогии, проверяем, что длинна каждого элемента равна 4. Если хоть один выбивается, будет False.
- Собираем все проверки через
all. Вместо all можно использовать and:
~any(s.duplicated()) and all(s.str.isnumeric()) and all(s.str.len() == 4)
Но для компактности по ширине, да и, в общем-то, читаемости, мне больше нравится вариант с all.