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.

\$\endgroup\$
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)
\$\endgroup\$
  • \$\begingroup\$ Thanks. It helps to know other efficient approach to solve a problem. :) \$\endgroup\$ – mishsx Jul 10 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.

\$\endgroup\$
  • 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\$ – Matthias Huschle Jul 9 at 16:04

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.