Skip to content

Instantly share code, notes, and snippets.

@scabbiaza
Last active June 12, 2017 10:16
Show Gist options
  • Save scabbiaza/87359d410e2f40a39a5c18a1fcb64b3a to your computer and use it in GitHub Desktop.
Save scabbiaza/87359d410e2f40a39a5c18a1fcb64b3a to your computer and use it in GitHub Desktop.
Functional programming
// http://paqmind.com/posts/fluent-api-debunked/
var R = require("ramda");
var sales = [
{id: 1, price: "500"},
{id: 2, price: "1500"},
{id: 3, price: "750"},
{id: 4, price: "1750"},
{id: 5, price: "150"},
{id: 3, price: "750"},
];
// Get list of prices of saled products that are below 1000, ordered by ASC
// Use filter, map and sort Object methods
var result1 = sales
.filter(item => item.price < 1000)
.sort((item1, item2) => item1.price > item2.price ? 1 : -1)
.map(item => item.price);
console.log('result1:', result1); // ["150", "500", "750", "750"]
// Get unique list of prices
var result2 = sales.filter(item => item.price < 1000);
result2 = R.uniq(result2);
result2 = result2.sort((item1, item2) => item1.price > item2.price ? 1 : -1)
.map(item => item.price);
console.log('result2:', result2); // ["150", "500", "750"]
// method composition is broken
// we cannot extend Object class with new behavior
// we also have mutability effect
// Functional approach
var result3 = R.pipe(
R.filter(item => item.price < 1000),
R.uniq,
R.sort((item1, item2) => item1.price > item2.price ? 1 : -1),
R.map(item => item.price)
)(sales);
console.log('result3:', result3); // ["150", "500", "750"]
// function composition is easy to extend
// no mutability effect
var R = require("ramda");
// get top 3 vetted Frontend Developers names,
// who completed hackerrank with the score >=90
// ordered by rate: from lower to higher.
var hackerrankResults = [
{hackerrank: 90, name: "Maria", category: "Frontend", vetted: true, rate: "1000"},
{hackerrank: 20, name: "Maria", category: "Frontend", vetted: true, rate: "1000"},
{hackerrank: 100, name: "Maria", category: "Frontend", vetted: true, rate: "1000"},
{hackerrank: 100, name: "Galina", category: "Frontend", vetted: true, rate: "2000"},
{hackerrank: 95, name: "Olga", category: "Frontend", vetted: true, rate: "3000"},
{hackerrank: 65, name: "Ira", category: "Frontend", vetted: true, rate: "3000"},
{hackerrank: 100, name: "Vika", category: "Frontend", vetted: false, rate: "1000"},
{hackerrank: 100, name: "Nadya", category: "Backend", vetted: true, rate: "1000"},
];
// expected result:
// Maria, Galina, Olga
//
// should not be in results:
// Nadya -> backend
// Vika -> not vetted
// Ira -> low hackerrank
// Maria should be in the rating only once
var filterPred = R.where({
vetted: R.equals(true),
category: R.equals("Frontend"),
hackerrank: R.gte(R.__, 90),
});
var sortByRate = R.sortBy(R.prop("rate"));
var accepted = R.pipe(R.filter(filterPred), R.uniqBy(R.prop("name")), sortByRate);
var top = R.take(3, R.map(R.prop("name"), accepted(hackerrankResults)));
console.log("top:", top); // Maria, Galina, Olga
// Mutability problem
let R = require("ramda");
let sales = [
{id: 1, price: "500"},
{id: 2, price: "1500"},
{id: 3, price: "750"},
{id: 4, price: "1750"},
{id: 5, price: "150"},
{id: 3, price: "750"},
];
// Get list of saled products that are below 1000, ordered by ASC
let result1 = R.pipe(
R.filter(item => item.price < 1000),
R.uniq,
R.sort((item1, item2) => item1.price > item2.price ? 1 : -1)
)(sales);
console.log('result1:\n', result1);
console.log('sales:', sales);
// Get list of saled products that are below 1000, ordered by ASC
// Convert prices to prices with taxes
let result2 = R.pipe(
R.filter(item => item.price < 1000),
R.uniq,
R.sort((item1, item2) => item1.price > item2.price ? 1 : -1),
R.map(item => {
item.priceWithTax = item.price * 1.2;
return item;
})
)(sales);
console.log('result2:\n', result2);
console.log('sales:', sales);
// RESULT
$ babel-node test.js
result1:
[ { id: 5, price: '150' },
{ id: 1, price: '500' },
{ id: 3, price: '750' } ]
sales: [ { id: 1, price: '500' },
{ id: 2, price: '1500' },
{ id: 3, price: '750' },
{ id: 4, price: '1750' },
{ id: 5, price: '150' },
{ id: 3, price: '750' } ]
result2:
[ { id: 5, price: '150', priceWithTax: 180 },
{ id: 1, price: '500', priceWithTax: 600 },
{ id: 3, price: '750', priceWithTax: 900 } ]
sales: [ { id: 1, price: '500', priceWithTax: 600 },
{ id: 2, price: '1500' },
{ id: 3, price: '750', priceWithTax: 900 },
{ id: 4, price: '1750' },
{ id: 5, price: '150', priceWithTax: 180 },
{ id: 3, price: '750' } ]
// Mutability solution: don't use operation that do mutation
let R = require("ramda");
// Get list of saled products that are below 1000, ordered by ASC
// Convert prices to prices with taxes
let result2 = R.pipe(
R.filter(item => item.price < 1000),
R.uniq,
R.sort((item1, item2) => item1.price > item2.price ? 1 : -1),
R.map(item => {
item = R.assoc("priceWithTax", item.price * 1.2, item.price);
return item;
})
)(sales);
console.log('result2:\n', result2);
console.log('sales:', sales);
// Curry
let R = require("ramda");
let sum_v1 = function(a, b) {
return a + b;
}
console.log('sum_v1(2, 3)', sum_v1(2, 3));
let sum_v2 = function(a) {
return function(b) {
return a + b;
}
}
console.log('sum_v2(2)(3):', sum_v2(2)(3));
let add5 = sum_v2(5);
console.log('add5(1):', add5(1));
console.log('add5(2):', add5(2));
console.log('add5(3):', add5(3));
let sum_v3 = R.curry(function(a, b) {
return a + b;
});
let add6 = sum_v3(6);
console.log('add6(1):', add6(1));
console.log('add6(2):', add6(2));
console.log('add6(3):', add6(3));
// Summary
// 1. No option variables
// 2. Think about data order!
// How to use curry functions
let numbers = [1, 2, 3, 4, 5];
console.log('numbers.map(add6):', numbers.map(add6));
// _.map(numbers, add6) will not work
console.log('R.map(add6, numbers):', R.map(add6, numbers));
let mapAdd6 = R.map(add6);
console.log('mapAdd6(numbers):', mapAdd6(numbers));
// Curry
let R = require("ramda");
var hackerrankResults = [
{hackerrank: 90, name: "Maria", category: "Frontend", vetted: true, rate: "1000"},
{hackerrank: 20, name: "Maria", category: "Frontend", vetted: true, rate: "1000"},
{hackerrank: 100, name: "Maria", category: "Frontend", vetted: true, rate: "1000"},
{hackerrank: 100, name: "Galina", category: "Frontend", vetted: true, rate: "2000"},
{hackerrank: 95, name: "Olga", category: "Frontend", vetted: true, rate: "3000"},
{hackerrank: 65, name: "Ira", category: "Frontend", vetted: true, rate: "3000"},
{hackerrank: 100, name: "Vika", category: "Frontend", vetted: false, rate: "1000"},
{hackerrank: 100, name: "Nadya", category: "Backend", vetted: true, rate: "1000"},
];
//let isVetted = function(user) {return user.vetted};
let isVetted = R.whereEq({vetted: true});
let isFrontend = R.whereEq({category: "Frontend"});
//let result = R.filter(isFrontend, hackerrankResults);
let result = R.pipe(
R.filter(isVetted),
R.filter(isFrontend)
)(hackerrankResults);
console.log('result:', result);
// Try to do
// 1. create isCategoryAsDefined predicate function
// 2. Try to remove double looping in example above
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment