Median Paycheck: Exercise
Write a point-free function to find the median monthly paycheck above $100,000.
I hope this one looks familiar–it’s from our higher-order functions section!
Given a list of employee salaries, find the median monthly paycheck above $100,000.
Usage
const medianPaycheck = getMedianPaycheck(employees) // $141,000
The median’s $141,000?! Must be Google or Facebook employees…oh, by the way, your solution must be point-free. ;)
employees.js
export default [
{
"name": "User 1",
"salary": 55042
},
{
"name": "User 2",
"salary": 74274
},
{
"name": "User 3",
"salary": 998323
},
{
"name": "User 4",
"salary": 97863
},
{
"name": "User 5",
"salary": 116609
},
{
"name": "User 6",
"salary": 402591
},
{
"name": "User 7",
"salary": 684812
},
{
"name": "User 8",
"salary": 135921
},
{
"name": "User 9",
"salary": 736885
},
{
"name": "User 10",
"salary": 85801
},
{
"name": "User 11",
"salary": 532593
},
{
"name": "User 12",
"salary": 64776
},
{
"name": "User 13",
"salary": 71243
},
{
"name": "User 14",
"salary": 740326
},
{
"name": "User 15",
"salary": 1039627
},
{
"name": "User 16",
"salary": 243305
},
{
"name": "User 17",
"salary": 957457
},
{
"name": "User 18",
"salary": 100250
},
{
"name": "User 19",
"salary": 24994
},
{
"name": "User 20",
"salary": 71097
}
];
solution
import { filter, lte, pipe, pluck,median, divide,flip } from 'ramda';
import employees from './employees.js';
const toUSD = x=>x.toLocaleString("en-US",{
style:"currency",
currency:"USD"
})
const getMedianPaycheck = pipe(
pluck("salary"),
filter(lte(100000)),
x=>{console.log(x);return x},
median,
flip(divide)(12),
toUSD
);
const medianPaycheck = getMedianPaycheck(employees) // $141,000
console.log(medianPaycheck)
Median Paycheck: Solution Review
Solution review.
I hope you didn’t cheat and look at the HOFs section to find this snippet. :D
Either way, let’s list the steps
- Get salaries
- Reject anything below $100,000
- Get the median
- Calculate monthly paycheck (amount / 12 months)
- Format dollars (USD)
I think we’re comfortable enough to start with a Ramda solution
import { filter, map, median, pipe, prop } from 'ramda';
import employees from './employees';
const toUSD = (amount) => amount.toLocaleString('en-US', {
style: 'currency',
currency: 'USD',
});
const getMedianPaycheck = pipe(
map(prop('salary')),
filter((amount) => amount >= 100000),
median,
(amount) => amount / 12,
toUSD
);
const result = getMedianPaycheck(employees);
console.log({ result });
Remember, pluck(‘salary’) is equivalent to map(prop(‘salary’)).
import { filter, median, pipe, pluck } from 'ramda';
import employees from './employees';
const toUSD = (amount) => amount.toLocaleString('en-US', {
style: 'currency',
currency: 'USD',
});
const getMedianPaycheck = pipe(
pluck('salary'),
filter((amount) => amount >= 100000),
median,
(amount) => amount / 12,
toUSD
);
const result = getMedianPaycheck(employees);
console.log({ result });
And R.lte is great for filtering the salaries.
import { filter, lte, median, pipe, pluck } from 'ramda';
import employees from './employees';
const toUSD = (amount) => amount.toLocaleString('en-US', {
style: 'currency',
currency: 'USD',
});
const getMedianPaycheck = pipe(
pluck('salary'),
filter(lte(100000)),
median,
(amount) => amount / 12,
toUSD
);
const result = getMedianPaycheck(employees);
console.log({ result });
Ramda has a divide function, but it doesn’t work as expected.
import { divide, filter, lte, median, pipe, pluck } from 'ramda';
import employees from './employees';
const toUSD = (amount) => amount.toLocaleString('en-US', {
style: 'currency',
currency: 'USD',
});
const getMedianPaycheck = pipe(
pluck('salary'),
filter(lte(100000)),
median,
divide(12),
toUSD
);
const result = getMedianPaycheck(employees);
console.log({ result });
$0.00?! That doesn’t look right. Let’s inspect with tap.
import { divide, filter, lte, median, pipe, pluck, tap } from 'ramda';
import employees from './employees';
const toUSD = (amount) => amount.toLocaleString('en-US', {
style: 'currency',
currency: 'USD',
});
const getMedianPaycheck = pipe(
pluck('salary'),
filter(lte(100000)),
median,
tap((value) => {
console.log('Before divide:', value);
}),
divide(12),
tap((value) => {
console.log('After divide:', value);
}),
toUSD
);
const result = getMedianPaycheck(employees);
console.log({ result });
Aha! We’re dividing 12 by 608702.5 and getting a tiny decimal that rounds to $0.00! But we want to flip that division! Sounds like a job for Ramda’s flip function.
import { divide, filter, flip, lte, median, pipe, pluck, tap } from 'ramda';
import employees from './employees';
const toUSD = (amount) => amount.toLocaleString('en-US', {
style: 'currency',
currency: 'USD',
});
const flippedDivide = flip(divide);
const getMedianPaycheck = pipe(
pluck('salary'),
filter(lte(100000)),
median,
flippedDivide(12),
toUSD
);
const result = getMedianPaycheck(employees);
console.log({ result });
Looks good to me! flip takes a function and returns a new one with the first two arguments reversed.
https://ramdajs.com/docs/#flip
Again, I wouldn’t do this in the real world. The point’s to expose you to Ramda’s toolkit and let you decide what’s best for your application.