diff --git a/Doc/tutorial/datastructures.rst b/Doc/tutorial/datastructures.rst --- a/Doc/tutorial/datastructures.rst +++ b/Doc/tutorial/datastructures.rst @@ -235,14 +235,49 @@ List Comprehensions ------------------- -List comprehensions provide a concise way to create lists without resorting to -use of :func:`map`, :func:`filter` and/or :keyword:`lambda`. The resulting list -definition tends often to be clearer than lists built using those constructs. + +List comprehensions provide a concise way to create lists without having to use +either an empty list populated with :meth:`list.append` in a :keyword:`for` +loop, or combinations of :func:`map`, :func:`filter`, and :keyword:`lambda`. +For example, assume we want to create a list of squares, like:: + + >>> squares = [] + >>> for x in range(10): + ... squares.append(x**2) + ... + >>> squares + [0, 1, 4, 9, 16, 25, 36, 49, 64, 81] + +We can obtain the same result with:: + + squares = [x**2 for x in range(10)] + +This is also equivalent to ``squares = map(lambda x: x**2, range(10))``, +but it's more concise and readable. + Each list comprehension consists of an expression followed by a :keyword:`for` clause, then zero or more :keyword:`for` or :keyword:`if` clauses. The result will be a list resulting from evaluating the expression in the context of the -:keyword:`for` and :keyword:`if` clauses which follow it. If the expression -would evaluate to a tuple, it must be parenthesized. :: +:keyword:`for` and :keyword:`if` clauses which follow it. For example, this +listcomp combines the elements of two lists if they are not equal:: + + >>> [(x, y) for x in [1,2,3] for y in [3,1,4] if x != y] + [(1, 3), (1, 4), (2, 3), (2, 1), (2, 4), (3, 1), (3, 4)] + +and it's equivalent to: + + >>> combs = [] + >>> for x in [1,2,3]: + ... for y in [3,1,4]: + ... if x != y: + ... combs.append((x, y)) + ... + >>> combs + [(1, 3), (1, 4), (2, 3), (2, 1), (2, 4), (3, 1), (3, 4)] + +Note how the order of the :keyword:`for` and :keyword:`if` statements is the +same in both these snippets. If the expression is a tuple (e.g. the ``(x, y)`` +in this example), it must be parenthesized. :: >>> freshfruit = [' banana', ' loganberry ', 'passion fruit '] >>> [weapon.strip() for weapon in freshfruit] @@ -275,45 +310,48 @@ List comprehensions are much more flexible than :func:`map` and can be applied to complex expressions and nested functions:: - >>> [str(round(355/113.0, i)) for i in range(1,6)] + >>> from math import pi + >>> [str(round(pi, i)) for i in range(1,6)] ['3.1', '3.14', '3.142', '3.1416', '3.14159'] Nested List Comprehensions -------------------------- -If you've got the stomach for it, list comprehensions can be nested. They are a -powerful tool but -- like all powerful tools -- they need to be used carefully, -if at all. +The initial expression in a list comprehension can be any arbitrary expression, +including another list comprehension. -Consider the following example of a 3x3 matrix held as a list containing three -lists, one list per row:: +Consider the following example of a 3x4 matrix implemented as a list of +3 lists of length 4:: - >>> mat = [ - ... [1, 2, 3], - ... [4, 5, 6], - ... [7, 8, 9], - ... ] + >>> matrix = [ + ... [1, 2, 3, 4], + ... [5, 6, 7, 8], + ... [9, 10, 11, 12], + ... ] -Now, if you wanted to swap rows and columns, you could use a list -comprehension:: +The following list comprehension will transpose rows and columns:: - >>> print [[row[i] for row in mat] for i in [0, 1, 2]] - [[1, 4, 7], [2, 5, 8], [3, 6, 9]] + >>> [[row[i] for row in mat] for i in range(4)] + [[1, 5, 9], [2, 6, 10], [3, 7, 11], [4, 8, 12]] -Special care has to be taken for the *nested* list comprehension: +As we saw in the previous section, the nested listcomp is evaluated in +the context of the :keyword:`for` that follows it, so this example is +equivalent to:: - To avoid apprehension when nesting list comprehensions, read from right to - left. + >>> transposed = [] + >>> for i in range(4): + ... # the following 3 lines implement the nested listcomp + ... transposed_row = [] + ... for row in matrix: + ... transposed_row.append(row[i]) + ... transposed.append(transposed_row) + ... + >>> transposed + [[1, 5, 9], [2, 6, 10], [3, 7, 11], [4, 8, 12]] -A more verbose version of this snippet shows the flow explicitly:: - for i in [0, 1, 2]: - for row in mat: - print row[i], - print - -In real world, you should prefer built-in functions to complex flow statements. +In the real world, you should prefer built-in functions to complex flow statements. The :func:`zip` function would do a great job for this use case:: >>> zip(*mat)