Originally inspired from this blog post. But many have been customized and rewritten into an IPython Notebook.

Note: Written for Python 3

## Unpacking

```a, b, c = 1, 2, 3

a, b, c

(1, 2, 3)
```
```a, b, c = [1, 2, 3]

a, b, c
(1, 2, 3)
```
```a, b, c = (2 * i + 1 for i in range(3))
a, b, c
(1, 3, 5)
```
```a, (b, c), d = [1, (2, 3), 4]

a, b, c, d
(1, 2, 3, 4)
```

## Iterating over list index and value pairs (enumerate)

```a = ['Hello', 'world', '!']

for i, x in enumerate(a):
print('{}: {}'.format(i, x)).. code-block:: python

0: Hello
1: world
2: !
```

## Zipping and unzipping lists and iterables

```a = [ 1,   2,   3 ]
b = ['a', 'b', 'c']
z = zip(a, b)

list(zip(*z))
[(1, 2, 3), ('a', 'b', 'c')]
```

## Grouping adjacent list items using zip

```a = [1, 2, 3, 4, 5, 6]

# Using iterators
group_adjacent = lambda a, k: list(zip(*([iter(a)] * k)))

[(1, 2, 3), (4, 5, 6)]
```
```group_adjacent(a, 2)
[(1, 2), (3, 4), (5, 6)]
```
```group_adjacent(a, 1)
[(1,), (2,), (3,), (4,), (5,), (6,)]
```
```# Using slices
from itertools import islice

group_adjacent = lambda a, k: list(zip(*(islice(a, i, None, k) for i in range(k))))

[(1, 2, 3), (4, 5, 6)]
```
```group_adjacent(a, 2)
[(1, 2), (3, 4), (5, 6)]
```
```group_adjacent(a, 1)
[(1,), (2,), (3,), (4,), (5,), (6,)]
```

## Sliding windows (n-grams) using zip and iterators

```from itertools import islice
def n_grams(a, n):
z = (islice(a, i, None) for i in range(n))
return list(zip(*z))

a = [1, 2, 3, 4, 5, 6]

n_grams(a, 3)
```
```[(1, 2, 3), (2, 3, 4), (3, 4, 5), (4, 5, 6)]

n_grams(a, 2)
[(1, 2), (2, 3), (3, 4), (4, 5), (5, 6)]
```
```n_grams(a, 4)
[(1, 2, 3, 4), (2, 3, 4, 5), (3, 4, 5, 6)]
```

## Inverting a dictionary using zip

```m = {'a': 1, 'b': 2, 'c': 3, 'd': 4}

# Assuming all values are immutable types
mi = dict(zip(m.values(), m.keys()))

mi
{1: 'a', 2: 'b', 3: 'c', 4: 'd'}
```

## List Flattening

```nest = [[1, 2], [3, 4], [5, 6]]
```

Using chain

```>>> from itertools import chain
>>> list(chain.from_iterable(nest))
[1, 2, 3, 4, 5, 6]
```

Using sum

```>>> sum(nest, [])
[1, 2, 3, 4, 5, 6]
```

Using List Comprehensions

```>>> [l for n in nest for l in n]
[1, 2, 3, 4, 5, 6]
```

What the evil voodoo magic is this?!

Better to think of it this way

Go back to basics

```# Normal List Comp
>>> [n for n in nest]
[[1, 2], [3, 4], [5, 6]]

List Comp Inside List Comp
```
```# list comp-inception
>>> [[l for l in n] for n in nest]
[[1, 2], [3, 4], [5, 6]]
```

Now Split Up Components

```[l for l in n]    => [l, l],  [l, l]
[n for n in nest] => [[n], [n], [n]]
```

Map out the Logic

```[Part A]   for-every  [Part B]
[l for n in nest] for [l in n]
```

Reduce Final Solution

```A: Get l for n in nest
[l for n in nest] => [l, l, l]

B: for every l in n
[l in n]          => [l, l]

[l for n in nest for l in n] => [l, l, l] X [l, l]
```
```# Random Nested List
a = [1, 2, [3, 4], [[5, 6], [7, 8]]]

def flatten(nested):
return (
[x for l in nested for x in flatten(l)]
if isinstance(nested, list) else
[nested]
)

flatten(a)
[1, 2, 3, 4, 5, 6, 7, 8]
```

## Generator expressions

```g = (x ** 2 for x in range(10))

next(g), next(g), next(g), next(g)
(0, 1, 4, 9)
```

## Dictionary comprehensions

```m = {x: x ** 2 for x in range(5)}

m
{0: 0, 1: 1, 2: 4, 3: 9, 4: 16}
```
```m = {x: 'A' + str(x) for x in range(10)}

m
{0: 'A0',
1: 'A1',
2: 'A2',
3: 'A3',
4: 'A4',
5: 'A5',
6: 'A6',
7: 'A7',
8: 'A8',
9: 'A9'}
```

## Inverting a dictionary using a dictionary comprehension

```m = {'a': 1, 'b': 2, 'c': 3, 'd': 4}

{v: k for k, v in m.items()}
{1: 'a', 2: 'b', 3: 'c', 4: 'd'}
```

## 1.21: namedtuple

```from collections import namedtuple

Point = namedtuple('Point', ['x', 'y'])
point = Point(x=1.0, y=2.0)

point.x, point.y
(1.0, 2.0)
```

## Inheriting from namedtuple

```PointBaseClass = namedtuple('PointBaseClass', ['x', 'y'])

class Point(PointBaseClass):
__slots__ = ()
return Point((self.x + other.x), (self.y + other.y))

x = Point(1.0, 2.0)
y = Point(2.0, 3.0)

x + y
Point(x=3.0, y=5.0)
```

## set operations

```# Set Constructor
A = set()
B = set()

# Set Literal Notation
A = {1, 2, 3, 4}
B = {3, 4, 5, 6, 7}

# Set Converted from List
A_ = set([1, 2, 3, 4])
B_ = set([3, 4, 5, 6, 7])

A == A_ and B == B_
True
```
```# Union Operator
A | B
{1, 2, 3, 4, 5, 6, 7}
```
```# Intersection Operator
A & B
{3, 4}
```
```# Difference Operator
A - B
{1, 2}
```
```# Symmetric Difference Operator
A ^ B
{1, 2, 5, 6, 7}
```
```# Putting it Together
(A ^ B) == ((A - B) | (B - A))
True
```

## Multisets and multiset operations (collections.Counter)

```from collections import Counter

# Construct a Counter from a List
A = Counter([1, 2, 3])
B = Counter([2, 2, 3])
```
```# Union Operator
A | B
Counter({2: 2, 1: 1, 3: 1})
```
```# Intersection Operator
A & B
Counter({2: 1, 3: 1})
```
```# Addition Operator
A + B
Counter({2: 3, 3: 2, 1: 1})
```
```# Subtraction Operator
A - B, B - A
(Counter({1: 1}), Counter({2: 1}))
```

## Simple Dictionary Trees (Autovivification)

(See https://gist.github.com/hrldcpr/2012250 for more on this.)

```# Using `__missing__`
class Tree(dict):
def __missing__(self, key):
value = self[key] = type(self)()
return value

root = Tree()

print(json.dumps(root, sort_keys=True, indent=2, separators=(',', ': ')))
```
```{
"id": "file",
"close": {
"onclick": "close();",
"value": "Close"
},
"new": {
"onclick": "new();",
"value": "New"
},
"open": {
"onclick": "open();",
"value": "Open"
}
},
"value": "File"
}
}
```