# Custom higher-order functions

Functions like `sort`, `max`, or `min` can take arguments like `key=` that are functions and can determine their behavior. This makes the built-in functions `sort` and `max` way more powerful and generic. They can be used in many more scenarios than if they would only compare the values themselves without the `key=` argument.
We can create our own higher-order functions as well:
``````def modify(numbers, f):
res = [f(n) for n in numbers]
return res

print(modify([1, 2, 3], lambda x: x**2))   # [1, 4, 9]
print(modify([1, 2, 3], lambda x: -x))     # [-1, -2, -3]
print(modify([2, 0, 1], lambda x: 2 * x))  # [4, 0, 2]
print(modify([2, 0, 1], str))              # ['2', '0', '1']``````
Here we pass different functions as `f` to the higher-order function `modify`. The modify function creates a new list from the input one and returns the result. Note that we can even pass a function like `str` to the function as well. So, each element of the input list will get applied a `str()` function - `str(2)`, `str(0)`, `str(1)`.

#### Challenge

Implement a generic version of the `sum` function called `generic_sum` which will take a collection as the first argument (it can be a list, a set, or a list of tuples) and a function as a second argument that obtains a number from each element of the collection.
``````def generic_sum():
...

print(generic_sum([1, 2, 3], lambda x: x))                   # 6
print(generic_sum({1, 2, 3}, lambda x: x))                   # 6
print(generic_sum([(1, 3), (4, 6)], lambda x: x[0] + x[1]))  # 14``````

#### Constraints

Time limit: 2 seconds

Memory limit: 512 MB

Output limit: 1 MB