4
\$\begingroup\$

I had me a code challenge and I was thinking: is there a way to make this more efficient and short? The challenge requires me to scan a string and ...

  • In the first line, print True if it has any alphanumeric characters. Otherwise, print False.

  • In the second line, print True if it has any alphabetical characters. Otherwise, print False.

  • In the third line, print True if it has any digits. Otherwise, print False.

  • In the fourth line, print True if it has any lowercase characters. Otherwise, print False.

  • In the fifth line, print True if has any uppercase characters. Otherwise, print False.

Below is my approach :

def func_alnum(s):
 for i in s:
 if i.isalnum():
 return True
 return False
def func_isalpha(s):
 for i in s:
 if i.isalpha():
 return True
 return False
def func_isdigit(s):
 for i in s:
 if i.isdigit():
 return True
 return False 
def func_islower(s):
 for i in s:
 if i.islower():
 return True
 return False
def func_isupper(s):
 for i in s:
 if i.isupper():
 return True
 return False
if __name__ == '__main__':
 s = input()
 s=list(s)
 print(func_alnum(s))
 print(func_isalpha(s))
 print(func_isdigit(s))
 print(func_islower(s))
 print(func_isupper(s))

It feels like I made a mountain out of a molehill. But I would defer to your opinions on efficiency and shortness before I live with that opinion.

asked Jul 9, 2019 at 10:39
\$\endgroup\$

2 Answers 2

3
\$\begingroup\$

Your five functions only differ by the predicate used to test each character, so you could have a single one parametrized by said predicate:

def fulfill_condition(predicate, string):
 for character in string:
 if predicate(character):
 return True
 return False
if __name__ == '__main__':
 s = input()
 print(fulfill_condition(str.isalnum, s))
 print(fulfill_condition(str.isalpha, s))
 print(fulfill_condition(str.isdigit, s))
 print(fulfill_condition(str.islower, s))
 print(fulfill_condition(str.isupper, s))

Note that you don't need to convert the string to a list for this to work, strings are already iterables.

Now we can simplify fulfill_condition even further by analysing that it applies the predicate to each character and returns whether any one of them is True. This can be written:

def fulfill_condition(predicate, string):
 return any(map(predicate, string))

Lastly, if you really want to have 5 different functions, you can use functools.partial:

from functools import partial
func_alnum = partial(fulfill_condition, str.isalnum)
func_isalpha = partial(fulfill_condition, str.isalpha)
func_isdigit = partial(fulfill_condition, str.isdigit)
func_islower = partial(fulfill_condition, str.islower)
func_isupper = partial(fulfill_condition, str.isupper)
answered Jul 9, 2019 at 16:48
\$\endgroup\$
1
  • \$\begingroup\$ Thanks. It helps to know other efficient approach to solve a problem. :) \$\endgroup\$ Commented Jul 10, 2019 at 7:11
1
\$\begingroup\$

This is done using list comprehensions and any() in python.

We can use the following to make it more faster.

print(any([i.isalnum() for i in string]))

Since we are only looking for any 1 element in the string being an uppercase,lowercase, etc Any() finds a good use case here.

answered Jul 9, 2019 at 10:53
\$\endgroup\$
1
  • 2
    \$\begingroup\$ any can also take an iterator instead of a list. It stops the iteration as soon as it encounters a True element. So if you remove the square brackets, it's even faster. \$\endgroup\$ Commented Jul 9, 2019 at 16:04

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.