\[ [Index](index.md) | [Exercise 5.2](ex5_2.md) | [Exercise 5.4](ex5_4.md) \]

# Exercise 5.3

*Objectives:*

- Higher order functions

*Files Modified:* `reader.py`

## (a) Using higher-order functions

At the moment, the `reader.py` program consists of two core functions, `csv_as_dicts()` and
`csv_as_instances()`.   The code in these two functions is almost identical.  For example:

```python
def csv_as_dicts(lines, types, *, headers=None):
    '''
    Convert lines of CSV data into a list of dictionaries
    '''
    records = []
    rows = csv.reader(lines)
    if headers is None:
        headers = next(rows)
    for row in rows:
        record = { name: func(val)
                   for name, func, val in zip(headers, types, row) }
        records.append(record)
    return records

def csv_as_instances(lines, cls, *, headers=None):
    '''
    Convert lines of CSV data into a list of instances
    '''
    records = []
    rows = csv.reader(lines)
    if headers is None:
        headers = next(rows)
    for row in rows:
        record = cls.from_row(row)
        records.append(record)
    return records
```

Unify the core of these functions into a single function `convert_csv()` that accepts a user-defined
conversion function as an argument.  For example:

```python
>>> def make_dict(headers, row):
        return dict(zip(headers, row))

>>> lines = open('Data/portfolio.csv')
>>> convert_csv(lines, make_dict)
[{'name': 'AA', 'shares': '100', 'price': '32.20'}, {'name': 'IBM', 'shares': '50', 'price': '91.10'}, 
 {'name': 'CAT', 'shares': '150', 'price': '83.44'}, {'name': 'MSFT', 'shares': '200', 'price': '51.23'}, 
 {'name': 'GE', 'shares': '95', 'price': '40.37'}, {'name': 'MSFT', 'shares': '50', 'price': '65.10'}, 
 {'name': 'IBM', 'shares': '100', 'price': '70.44'}]
>>>
```

Rewrite the `csv_as_dicts()` and `csv_as_instances()` functions in terms of the new `convert_csv()`
function.

## (b) Mapping

One of the most common operations in functional programming is the `map()` operation that maps a function
to the values in a sequence.  Python has a built-in `map()` function that does this.  For
example:

```python
>>> nums = [1,2,3,4]
>>> squares = map(lambda x: x*x, nums)
>>> for n in squares:
        print(n)

1
4
9
16
>>>
```

`map()` produces an iterator so if you want a list, you'll need to create it explicitly:

```python
>>> squares = list(map(lambda x: x*x, nums))
>>> squares
[1, 4, 9, 16]
>>>
```

Try to use `map()` in your `convert_csv()` function.

\[ [Solution](soln5_3.md) | [Index](index.md) | [Exercise 5.2](ex5_2.md) | [Exercise 5.4](ex5_4.md) \]

----
`>>>` Advanced Python Mastery  
`...` A course by [dabeaz](https://www.dabeaz.com)  
`...` Copyright 2007-2023  

![](https://i.creativecommons.org/l/by-sa/4.0/88x31.png). This work is licensed under a [Creative Commons Attribution-ShareAlike 4.0 International License](http://creativecommons.org/licenses/by-sa/4.0/)
