pythonstringpython-2.7pangram

How to check if string is a pangram?


I want to create a function which takes a string as input and check whether the string is pangram or not (pangram is a piece of text which contains every letter of the alphabet).

I wrote the following code, which works, but I am looking for an alternative way to do it, hopefully a shorted way.

import string

def is_pangram (gram):
    gram = gram.lower()
    gram_list_old = sorted([c for c in gram if c != ' '])
    gram_list = []
    for c in gram_list_old:
        if c not in gram_list:
            gram_list.append(c)
    if gram_list == list(string.ascii_lowercase): return True
    else: return False

I feel like this question might be against the rules of this website but hopefully it isn't. I am just curious and would like to see alternative ways to do this.


Solution

  • is_pangram = lambda s: not set('abcdefghijklmnopqrstuvwxyz') - set(s.lower())
    
    >>> is_pangram('abc')
    False
    >>> is_pangram('the quick brown fox jumps over the lazy dog')
    True
    >>> is_pangram('Does the quick brown fox jump over the lazy dog?')
    True
    >>> is_pangram('Do big jackdaws love my sphinx of quartz?')
    True
    

    Test string s is a pangram if we start with the alphabet, remove every letter found in the test string, and all the alphabet letters get removed.

    Explanation

    The use of 'lambda' is a way of creating a function, so it's a one line equivalent to writing a def like:

     def is_pangram(s):
         return not set('abcdefghijklmnopqrstuvwxyz') - set(s.lower())
    

    set() creates a data structure which can't have any duplicates in it, and here:

    Subtracting things like set(..) - set(..) returns the contents of the first set, minus the contents of the second set. set('abcde') - set('ace') == set('bd').

    In this pangram test:

    set(..) - set(..) will return an empty set, or a set with content. If we force sets into the simplest True/False values in Python, then containers with content are 'True' and empty containers are 'False'.

    So we're using not to check "is there anything leftover?" by forcing the result into a True/False value, depending on whether there's any leftovers or not.

    not also changes True -> False, and False -> True. Which is useful here, because (alphabet used up) -> an empty set which is False, but we want is_pangram to return True in that case. And vice-versa, (alphabet has some leftovers) -> a set of letters which is True, but we want is_pangram to return False for that.

    Then return that True/False result.

    is_pangram = lambda s: not set('abcdefghijklmnopqrstuvwxyz') - set(s.lower())
    #      Test string `s`
    #is a pangram if
    #                           the alphabet letters 
    #                                                             minus 
    #                                                               the test string letters
    #                   has NO leftovers