From f5d1ac7cbbe4e0d9a803f77771ade31f90f90e21 Mon Sep 17 00:00:00 2001 From: Mark Pilgrim Date: Sun, 12 Apr 2009 23:57:55 -0400 Subject: [PATCH] two more sections in advanced-iterators --- advanced-iterators.html | 40 ++++++++++++++++++++++++++++++---------- 1 file changed, 30 insertions(+), 10 deletions(-) diff --git a/advanced-iterators.html b/advanced-iterators.html index ae0f557..70885a0 100644 --- a/advanced-iterators.html +++ b/advanced-iterators.html @@ -70,33 +70,49 @@ if __name__ == '__main__':

Finding the unique items in a sequence

+

This section has nothing to do with iterators, but it's put to good use in the alphametics solver. Set comprehensions make it trivial to find the unique items in a sequence. +

 >>> a_list = ['a', 'c', 'b', 'a', 'd', 'b']
->>> {c for c in a_list}
+>>> {c for c in a_list}                      
 {'a', 'c', 'b', 'd'}
 >>> a_string = 'EAST IS EAST'
->>> {c for c in a_string}
+>>> {c for c in a_string}                    
 {'A', ' ', 'E', 'I', 'S', 'T'}
 >>> words = ['SEND', 'MORE', 'MONEY']
->>> ''.join(words)
+>>> ''.join(words)                           
 'SENDMOREMONEY'
->>> {c for c in ''.join(words)}
+>>> {c for c in ''.join(words)}              
 {'E', 'D', 'M', 'O', 'N', 'S', 'R', 'Y'}
+
    +
  1. Given a list of several strings, a set comprehension with the identity function will return a set of unique strings from the list. This makes sense if you think of it like a for loop. Take the first item from the list, put it in the set. Second. Third. Fourth — wait, that's in the set already, so it only gets listed once. Fifth. Sixth — again, a duplicate, so it only gets listed once. The end result? All the unique items in the original list, without any duplicates. The original list doesn't even need to be sorted first. +
  2. The same technique works with strings, since a string is just a sequence of characters. +
  3. Given a list of strings, ''.join(a_list) concatenates all the strings together into one. +
  4. So, given a list of strings, this set comprehension returns all the unique characters across all the strings, with no duplicates. +
-

FIXME +

The alphametics solver uses this technique to get a list of all the unique characters in the puzzle. + +

unique_characters = {c for c in ''.join(words)}
+ +

This list is later used to assign digits to characters as the solver iterates through the possible solutions.

Making assertions

-

FIXME +

Another quick note about a useful debugging tool that's not specific to iterators or generators. Like many programming languages, Python has an assert statement. Here's how it works.

->>> assert 1 + 1 = 2
->>> assert 1 + 1 = 3
+>>> assert 1 + 1 == 2  
+>>> assert 1 + 1 == 3  
 Traceback (most recent call last):
   File "<stdin>", line 1, in 
 AssertionError
+
    +
  1. The assert statement is followed by any valid Python expression. In this case, the expression 1 + 1 == 2 evaluates to True, so the assert statement does nothing. +
  2. However, if the Python expression evaluates to False, the assert statement will raise an AssertionError. +
-

FIXME +

Therefore, this line of code:

assert len(unique_characters) <= 10
@@ -105,6 +121,10 @@ AssertionError
if len(unique_characters) > 10:
     raise AssertionError
+

But a bit easier to read and write. + +

The alphametics solver uses this exact assert statement to bail out early if the puzzle contains more than ten unique letters. Since each letter is assigned a unique digit, and there are only ten digits, a puzzle with more than ten unique letters is unsolvable. +

Generator objects

FIXME @@ -204,7 +224,7 @@ StopIteration >>> names ['Dora\n', 'Ethan\n', 'Wesley\n', 'John\n', 'Anne\n', 'Mike\n', 'Chris\n', 'Sarah\n', 'Alex\n', 'Lizzie\n'] ->>> names = [name[:-1] for name in names] +>>> names = [name.strip() for name in names] >>> names ['Dora', 'Ethan', 'Wesley', 'John', 'Anne', 'Mike', 'Chris', 'Sarah', 'Alex', 'Lizzie']