The Python community generally prefers list comprehensions to the functional programming ways of achieving the same goals.

Creating a list of squares:

In [ ]:

```
# regular way
squares = []
for x in range(10):
squares.append(x**2)
print(squares)
```

In [ ]:

```
# functional tools
squares = list(map(lambda x: x**2, range(10)))
print(squares)
```

In [ ]:

```
# list comprehension
squares = [x**2 for x in range(10)]
print(squares)
```

The structure of a list comprehension is the following:

**[** `expression`

`for-loop`

`for-loops and if-statements`

**]**

For example:

In [ ]:

```
combinations = [(x, y) for x in [1,2,3] for y in [3,1,4] if x != y]
print(combinations)
# expression: (x, y)
# first for-loop: for x in [1,2,3]
# more for-loops and if-statements: for y in [3,1,4] if x != y
```

In [ ]:

```
# equivalent code:
combinations = []
for x in [1,2,3]:
for y in [3,1,4]:
if x != y:
combinations.append((x, y))
print(combinations)
```

Out[ ]:

This way the `if`

statement in a list comprehension can replace a `filter`

.

In [ ]:

```
numbers = filter(lambda x: abs(x//10 - x%10) < 3, range(10, 40))
print(*numbers)
```

In [ ]:

```
numbers = [x for x in range(10, 40) if abs(x//10 - x%10) < 3]
print(*numbers)
```

The `expression`

in a list comprehension may be anything, including another list comprehension. This allows you to make nested list comprehensions to perform more complex actions. However, you should make sure that your code stays readable and that your list comprehensions don't cause too much confusion.

In [ ]:

```
matrix = [
[1, 2, 3, 4],
[5, 6, 7, 8],
[9, 10, 11, 12],
]
```

In [ ]:

```
[[row[i] for row in matrix] for i in range(4)]
```

Out[ ]:

In [ ]:

```
# the equivalent code (1 list comprehension):
transposed = []
for i in range(4):
transposed.append([row[i] for row in matrix])
print(transposed)
```

In [ ]:

```
# the equivalent (no list comprehensions)
transposed = []
for i in range(4):
transposed_row = []
for row in matrix:
transposed_row.append(row[i])
transposed.append(transposed_row)
print(transposed)
```

Write a program that flattens a matrix using a list comprehension.

Flattening means taking a nested list (a list of lists in case of a matrix) and turning it into a single list with all the elements of the matrix.

Solve Task 3 of Workshop 15 using list comprehensions. don't use any for loops outside of them.

You are given a list of data pairs. The first element of a pair is a year, the second one is a data point.

Split the data into groups by year using the `itertools.groupby()`

function. Then for every year output data points containing numbers over 1000. A list comprehension to do it.

Do not use any lists / tuples / sets / dictionaries as variables. Do not use any for-loops beside the one given below. Solve everything using `groupby`

and list comprehensions.

You can learn how to use `groupby`

here: https://docs.python.org/3.8/library/itertools.html#itertools.groupby

The key part is this:

```
for k, g in groupby(data, keyfunc):
```

Your output should be

```
Data for the year 1988
4636 1808 1108
Data for the year 1989
3517
Data for the year 1990
2276 2407 1798
```

Here is an example of a function that flattens a dictionary recursively, separating the keys of different levels with dots:

In [ ]:

```
def flatten_dict(d, prefix=None):
if prefix is None:
prefix = ''
result = {}
for k, v in d.items():
if isinstance(v, dict):
result.update(flatten_dict(v, k+'.'))
else:
result.update({prefix+k:v})
return result
```

Write a function that maps a function over a nested list

In [ ]:

```
def treemap(???):
???
print(treemap(lambda x: x*x, [[[1], [2, 3], 4], [5, 6], 7]))
# [[[1], [4, 9], 16], [25, 36], 49]
```

Write a function that does the opposite of the function `flatten_dict`

: given a dictionary with dots in keys it should create a nested dictionary where dots separate the levels.