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,000console.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.
