---
# System prepended metadata

title: Homework 2022-01-11

---

# Homework 2022-01-11

## Algorithms and Performance
We faced the following question: suppose we have a dictionary from security ids to account ids. Here is an example. For clarity, we will use letters to represent account ids and numbers to represent securities:
```python
org = {
    1: ['a'], 
    2: ['a'], 
    3: ['a', 'b'], 
    4: ['a', 'b'], 
    5: ['b', 'c'], 
    6: ['c']
}
```
We would like to hit the pricing-data endpoint, which will return analytics for any number of securities in a given account on a given date. 

1. Review: Invert this dictionary, such that it is a map from accounts to securities they hold. Call the new dictionary `inv`
```python=
inv = {}

for key, value in org.items():
    for v in value:
        if v not in inv:
            inv[v] = []
        inv[v].append(key)
```

2. Review: Write a program which will return the account with the most securities in it. For Tab and Nick, I recommend attempting to independently produce (ie without looking it up) something like Garrett's first answer.
3. Here is one possible implementation of problem 2: 
    ```python=
    def go(k): return len(inv[k])
    max_account = max(inv,key=go)
    ```
    Is this implementation faster than your implementation? Why or why not?
4. We go and hit pricing-data for that account. Suppose all their securities have the information we need for every security. Which should be the next account we hit?
5. Write a program which hits pricing-data for the minimal number of accounts. You can do this with a mocked function if you'd like:
    ```python
    def get_pricing_data(account, securities): 
        return {s:True for s in securities}
    ```
7. In reality it might be that we need to hit multiple accounts to cover the same security. Write a program which does this minimally. You can do this with a mocked function if you'd like:
    ```python
    def get_pricing_data(account, securities): 
        return {s:not (ord(account) + s) % 2 for s in securities}
    ```
    NB: even after running through all account/security combos you may not have the data you want for all securities
8. How well does your algorithm survive contact with `semaphore`? Suppose now that we want the fastest script by the clock. You can practice with this mocked function if you'd like (and probably should use a larger list of securities/accounts, like the one we get from running the script; if so, remove the `ord` function below):
    ```python
    import time
    import random
    def get_pricing_data(account, securities): 
        time.sleep(random.random() * len(securities)/25)
        return {s:not (ord(account) + s) % 2 for s in securities}
    ```

## Syntactic Sugar
NB: This section is somewhat academic and is primarily aimed at letting you "peek under the covers" of what the language is doing. You will use these tools a lot, but you can use them for very long without knowing the internals, and so you shouldn't worry too much about studying this section

This week we observed that `set([1,2,3]) - set([3,4,5]) = set([1,2])`. This is a different use of `-` than we normally see, where `4-3=1`. 

1. What are other examples of things you can use `-` on?

```python=
import pandas as pd
dat = [{"a":1},{"a":4}]
df = pd.DataFrame(dat)
dat2 = [{"a":4},{"a":-1}]
df2 = pd.DataFrame(dat2)

df-df2
```

3. This process is called "Operator Overloading". In python, these are implemented on "classes", which you will not have to worry about for years. In particular, `-` is defined by an object's `__sub__` method, while ie `+` is defined by the `__add__` method. It is important to understand that the `+` you see in python is very different from the `+` you see in normal math.
    1. One obvious example is that in python, `+` is not _commutative_ - that is, it is not generally true that `a+b=b+a`. We will look at some extreme examples below, but first, try to come up with example values for `a` and `b` such that `not (a+b==b+a)`.
    2. In what way is `datetime.date(2021,2,1) - datetime.date(2021,1,1)` not like normal subtraction?
    3. What is the result of `[1,2] + {3,4}`?
    4. What is the result of the following program:
    ```python=
    x = [1,2]
    x += {3,4}
    x
    ```
    5. Why?!?!
6. "Operator Overloading" is an example of a wider phenomena called "Syntactic Sugar". "Syntactic Sugar" is a phrase used to describe ways that programming languages translate human readable input into (usually) more verbose but equivalent programs. For instance, writing `"this"+"kiss"` is sytactic sugar for `"this".__add__("kiss")`. It is often useful to think about expressions and what they "desugar" into. For instance, while (as we saw above) the following is not quite true, to a first approximation you can read `x+=1` as `x=x+1`. 
    1. Suppose that `xss=[[1,2,3],[4,5],[6]]`. Write an expression that returns `[1,2,3,4,5,6]` using nested for loops.
    2. Write an expression that returns `[1,2,3,4,5,6]` using list comprehension.
    3. Write an expression that returns `[1,2,3,4,5,6]` using `sum`.
4. What are other examples of Sytantic Sugar in Python?