improve min/maxElementBy

instead of recalculating the f(max) every time, store it in a tuple we pass along. this way we guarantee we only have to pass every element through f once, in case f is time intensive this will save a lot of processing