# Level 2 Python collection comprehensions and other stuff

##Stuff that pleasantly surprised me about python coming from C

Note: the examples here are from ipython. `In [<line no>]`

means input and `Out [<line no>]`

is output.

###Conditional Expressions

C style tenary operator(`condition?value_if_true : value_if_false`

), but in English.
The conditional expression returns one value if a condition is true or else it returns something else.

some arbitrary examples.

### List Comprehensions

This is a way to construct lists on the fly. Say you want to make a list that contains the squares of first 10 natural numbers

###What you know:

###List comprehension way

It takes an if statement too!

You can construct a list of anything with this.

list of tuples of numbers and their squares for first 10 natural numbers:

###Anatomy of list comprehensions, and optional bling

### More comprehensions - dicts, sets and generator expressions.

**Dictionary Comprehension** : `{<key>:<value> for <item> in <iterable> }`

This lets you construct dictionaries.
For example, to find how many times each character in a string repeats, one can do this:

**Set comprehensions**: `{<member> for <item> in <iterable>}`

This lets you create a set. A set is a data structure that do not allow repeats(only unique values) and are optimized for fast membership tests(which of the elements of SET A are also members of SET B?) and other related computations.

Say, if we have a list of strings `['parrot','dead','argument','spam','eggs','spam']`

and we need to find out the unique lengths. ie there are strings of length 8,4 and 6 in the list and no other length strings.

**Generator expressions**: `(<item to yield> for <item> in <iterable>)`

A generator expression is a lazy list comprehension. What this means is that the entire list is not stored in memory and when you iterate through it, the values are calculated just when they are needed. the difference between list comprehensions and generator expressions is also the difference between `range()`

and `xrange()`

from the standard library. A lot of the times, you do not need every item in a list at the same time, and using generator expressions at these times can save quite a bit of memory. For example , if you need the sum of the squares of the first 100 natural numbers, you do not need to store all the squares at any point. You only need an accumulator variable to store the total and the current square in the iteration.

Note that `sum()`

does not convert the argument into a list and works lazily.

###splat(`*`

) and double splat(`**`

)

**splat**:

While passing arguments in a function call, the splat `*`

operator is a signal to unpack.
Say you have a function that needs 3 arguments `def foo(arg1,arg2,arg3)`

, but while calling it, you have the arguments to send in a list, you can do the following

It works the other way around too, and allows you to send an arbitary number of arguments to a function.

You are encouraged to experiment with this stuff till you get a solid idea.

**double splat**:

the double splat(`**`

) is similar to the splat, just that it allows keyword arguments. You can arbitrarily pass keyword arguments and the function receives it as a dictionary.

other way round:

###zip
Docstring:
`zip(seq1 [, seq2 [...]]) -> [(seq1[0], seq2[0] ...), (...)]`

Return a list of tuples, where each tuple contains the i-th element from each of the argument sequences. The returned list is truncated in length to the length of the shortest argument sequence.

The opposite operation of this, where you have a list of tuples and you want a tuple of lists where each list

The combination of all this lets you do a lot of cool stuff.

###lambdas

A lambda is simply a function maker which lets you make oneline functions that return one expression. This expression can be conditional expressions or list comprehensions or whatever.

Is equivalent to

you can also call it directly without assigning to a variable.

###random example
Suppose you have a bunch of 2D coordinates as a list of tuples `[(x1,y1),(x2,y2),(x3,y3)....]`

and you want to find out the minimum x, maximum x, minimum y and maximum y.

`zip(*coords)`

unzips coords into `[(x1,x2,x3,x4...),(y1,y2,y3,y4...)]`

`map(<function or lambda>,iterable)`

returns a list of new values by applying the function on each value of the iterable
`lambda p:(max(p),min(p))`

takes an iterable and returns a tuple of the maximum and the minimum item in the list

Automatic unpacking causes the output of map to be assigned properly to the tuple of tuples in the left hand side.