Last active
November 11, 2022 20:14
-
-
Save azendal/451a4447dd51f8eb48be11ff47b7f521 to your computer and use it in GitHub Desktop.
filter, map, reduce intro
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
Applications filter -> Map -> Reduce and how it relates to functional | |
(Not a functional programming talk) | |
But a lil functional code | |
*/ | |
/* | |
A disclaimer on arrow functions | |
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions | |
no bind, this, call, apply | |
should be for single statements (this is where they actually shine) | |
no replacement for function declaration or function expression | |
were not designed as a short syntax to save strokes | |
good for filter, map, reduce, forEach | |
*/ | |
// utility fns | |
var getUid = function(length) { | |
var i, uid, min, max; | |
length = length || 32; | |
uid = ''; | |
min = 0; | |
max = getUid.codes.length - 1; | |
for (i = 0; i < length; i++) { | |
uid += getUid.codes[Math.floor(Math.random() * (max - min + 1)) + min]; | |
} | |
return uid; | |
}; | |
getUid.codes = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z']; | |
var benchmark = function (fn) { | |
return function (...rest) { | |
var s = Date.now(); | |
var r = fn(rest); | |
var e = Date.now(); | |
return [r, e - s]; | |
} | |
}; | |
var byProperty = function (property, value) { | |
return x => x[property] === value; | |
} | |
var intersection = (a, b) => a.filter(x => b.includes(x) === true); | |
var randomBetween = (min, max) => Math.floor(Math.random() * (max - min + 1) + min); | |
var randomCase = (cases) => cases[randomBetween(0, cases.length - 1)]; | |
var clamp = (a, min = 0, max = 1) => Math.min(max, Math.max(min, a)); | |
var lerp = (start, end, amt) => (1 - amt) * start + amt * end; | |
var invLerp = (x, y, a) => clamp((a - x) / (y - x)); | |
var reScale = (o, n, x) => lerp(n[0], n[1], invLerp(o[0], o[1], x)); | |
var log = x => { console.log(x); return x } | |
var identity = x => x; | |
var sum = x => x.reduce( (p, c) => p + c, 0 ); | |
var average = x => sum(x) / x.length; | |
var min = x => x.reduce( (p,c) => Math.min(p,c), Infinity ); | |
var max = x => x.reduce( (p,c) => Math.max(p,c), -Infinity ); | |
var chart = x => console.log('\n' + x.map(x => x.join('')).join('\n') + '\n'); | |
var byNeighborhood = (data, x) => data.filter(h => h.neighborhood == x); | |
var repeatTimes = (fn, times) => Array.from(Array(times)).map((x, i) => fn(x, i)); | |
var pipe = (...fns) => (x) => fns.reduce((v, f) => f(v), x); | |
var compose = (...fns) => x => fns.reduceRight((acc, fn) => fn(acc), x); | |
var composeAsync = (...fns) => input => fns.reduceRight((chain, func) => chain.then(func), Promise.resolve(input)); | |
var pipeAsync = (...fns) => input => fns.reduce((chain, func) => chain.then(func), Promise.resolve(input)); | |
/* | |
Filtering functions | |
This functions return the outcome of a comparison statement | |
*/ | |
var isNotEmpyString = x => x != ''; | |
var isInAmericana = x => x.neighborhood == 'Americana'; | |
var isInCentro = x => x.neighborhood == 'Centro'; | |
var twoRoomsOrMore = x => x.rooms >= 2; | |
/* | |
Maping functions | |
This functions return a transformed value | |
*/ | |
var onlyPrice = x => x.price; | |
var trimString = x => x.trim(); | |
/* | |
Reducing functions | |
This functions return a transformed value | |
*/ | |
var min_ = [(p,c) => Math.min(p,c), Infinity]; | |
var max_ = [(p,c) => Math.max(p,c), -Infinity]; | |
var average_ = [(p,c,i,a) => i === a.length - 1 ? p+c/a.length : p+c, 0]; | |
var neighborhoods_raw = ` | |
Centro | |
Providencia | |
Jardines Universidad | |
La Calma/Pinar | |
La Estancia | |
Americana | |
Santa Teresita | |
Ciudad Granja | |
San Pedro Tlaquepaque | |
Moderna | |
`; | |
var neighborhoods = neighborhoods_raw.split('\n').filter(isNotEmpyString).map(trimString); | |
var buildHouse = function () { | |
return { | |
id: getUid(), | |
neighborhood: randomCase(neighborhoods), | |
rooms: randomBetween(1,4), | |
parking: randomBetween(0,3), | |
price: randomBetween(1000000, 4000000) | |
} | |
} | |
// var data = [ | |
// {id: '89asdjdas897das', neighborhood: 'neighborhood1', rooms:2, parking:0, price: 700000} | |
//] | |
var buildDatabase = function () { | |
return Array.from(Array(1000)).map(buildHouse) | |
}; | |
console.log("Benchmarking database build") | |
console.table(repeatTimes(benchmark(buildDatabase), 10)); | |
var data = Array.from(Array(1000)).map(buildHouse); | |
console.log('Database') | |
console.table(data); | |
/* | |
Usage | |
This are sequences of filter -> map -> reduce functions | |
*/ | |
var cheapestInAmericana = data.filter(isInAmericana).map(onlyPrice).reduce(...min_); | |
console.log('cheapestInAmericana', cheapestInAmericana) | |
var familyHouseInAmericana = x => isInAmericana(x) && twoRoomsOrMore(x); | |
var averageTwoRooms = data.filter(familyHouseInAmericana).map(onlyPrice).reduce(...average_); | |
console.log('averageTwoRooms', averageTwoRooms) | |
var downTownHouses = data.filter(isInCentro); | |
console.log('downTownHouses') | |
console.table(downTownHouses) | |
var prices = downTownHouses.map(x => x.price); | |
console.log('AveragePrice', prices.reduce(...average_).toFixed(2)) | |
console.log('Max Price', prices.reduce(...max_)) | |
console.log('Min Price', prices.reduce(...min_)) | |
//where are more houses? | |
var index = {}; | |
var toIndex = (x) => typeof index[x.neighborhood] == 'undefined' ? index[x.neighborhood] = 1 : index[x.neighborhood] += 1; | |
data.forEach(toIndex) | |
console.table(index) | |
var maxByValue = (a,b) => a.value <= b.value ? b : a; | |
var fromEntrytoObj = ([k,v]) => { return {neighborhood: k, value: v} }; | |
var _maxByValue = [maxByValue, {value:-Infinity}] | |
var mostAvailable = Object.entries(index).map(fromEntrytoObj).reduce(..._maxByValue) | |
console.log("Most availability", mostAvailable) | |
console.log("The full flow") | |
// get the cheapest house in a neighborhood | |
// filter map reduce | |
var cheapHouse = data.filter(isInAmericana).map(x => x.price).reduce(...min_) | |
console.log('Best Price', cheapHouse) | |
//Bonus | |
function histogram(X, binRange) { | |
//inclusive of the first number | |
var max = Math.max(...X); | |
var min = Math.min(...X); | |
var len = max - min + 1; | |
var numberOfBins = Math.ceil(len / binRange); | |
var bins = new Array(numberOfBins).fill(0); | |
//-min to normalise values for the array | |
X.forEach((x) => bins[Math.floor((x-min) / binRange)]++); | |
return bins; | |
} | |
chart( histogram(prices, 100000).map(x => new Array(x).fill('#')) ); | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment