Skip to content

Instantly share code, notes, and snippets.

@azendal
Last active November 11, 2022 20:14
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save azendal/451a4447dd51f8eb48be11ff47b7f521 to your computer and use it in GitHub Desktop.
Save azendal/451a4447dd51f8eb48be11ff47b7f521 to your computer and use it in GitHub Desktop.
filter, map, reduce intro
/*
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