Now, there's a slight semantic difference, but instead of "removing what doesn't matter" you can choose to "keep what matters" with a set comprehension!
With this shift in mindset we can use something like `str.isalpha` to only keep "letter" characters:
Another good archetype of solution is to go through the letters that we want to find and see if they are inside the input string or not.
This solution is easy to understand and IMO superior to the raw `for` loop because it makes idiomatic use of the `all` built-in...
But this solution is not optimal!
If you have a really long string and the letters of the alphabet are towards the end of the input, then the usage of `in` will do a lot of work...
Think about strings starting with
`"_" * 1_000_000`,
you have to skip a million irrelevant "_".
So it really is helpful if we only traverse the input string once, so let's stick to solutions using sets.
There are many ways to phrase the solution using many equivalent formulations using set operations.
Here is an example:
However, my favourite solution, the one that I find most elegant, just checks if the set of lowercase letters is a subset of the set of all characters of the string!
This entails minimal preparation, it's just a single check:
The <= inequality is akin to the β in mathematical notation; if A and B are Python sets,
A <= B
checks if A is a subset of B.
This is the same as A.issubset(B).
This type of solution also makes it very easy to make our solution much more robust, e.g. handling accents in letters.
For example, let's say that the following should also be a pangram:
Γ bΓ§dΓͺfghΓjklmΓ±Γ΅pqrstΓΌvwxyz
Using `unicodedata.normalize` we can handle that!
I can't guarantee that the normalisation step above is the ABSOLUTE BEST, especially because I'm not a master of Unicode, but you can read always read the docs.
The normalisation above splits letters and accents: