Last active
July 22, 2018 14:13
-
-
Save daliborgogic/d3bcfe414af3f5a13d2d126fd4aadc08 to your computer and use it in GitHub Desktop.
Functional JavaScript [idiomatic]
This file contains hidden or 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
// Array utils ///////////////////////////////////////////////////////////////// | |
export const combine = (...arrays) => [].concat(...arrays) | |
export const compact = arr => arr.filter(Boolean) | |
export const contains = (() => Array.prototype.includes | |
? (arr, value) => arr.includes(value) | |
: (arr, value) => arr.some(el => el === value) | |
)() | |
export const difference = (arr, ...others) => { | |
var combined = [].concat(...others) | |
return arr.filter(el => !combined.some(exclude => el === exclude)) | |
} | |
export const head = arr => arr[0] | |
export const initial = arr => arr.slice(0, -1) | |
export const intersection = (...arrays) => | |
[...new Set([].concat(...arrays))].filter(toFind => | |
arrays.every(arr => arr.some(el => el === toFind)) | |
) | |
export const last = arr => arr.slice(-1)[0] | |
export const sortedIndex = (arr, value) => | |
[value].concat(arr).sort().indexOf(value) | |
export const tail = arr => arr.slice(1) | |
export const toArray = (() => Array.from ? Array.from : obj => [].slice.call(obj))() | |
export const union = (...arrays) => [...Set([].concat(...arrays))] | |
export const unique = arr => [...Set(arr)] | |
export const without = (arr, ...values) => | |
arr.filter(el => !values.some(exclude => el === exclude)) | |
// Object utils //////////////////////////////////////////////////////////////// | |
export const getValues = obj => Object.keys(obj).map(key => obj[key]) | |
export const merge = (() => { | |
const extend = Object.assign ? Object.assign : (target, ...sources) => { | |
sources.forEach(source => | |
Object.keys(source).forEach(prop => target[prop] = source[prop]) | |
) | |
return target | |
} | |
return (...objects) => extend({}, ...objects) | |
})() | |
export const toMap = (() => { | |
const convert = obj => new Map(Object.keys(obj).map(key => [key, obj[key]])) | |
return obj => obj instanceof Map ? obj : convert(obj) | |
})() | |
// Math //////////////////////////////////////////////////////////////////////// | |
export const min = arr => Math.min(...arr) | |
export const max = arr => Math.max(...arr) | |
export const sum = arr => arr.reduce((a, b) => a + b) | |
export const product = arr => arr.reduce((a, b) => a * b) | |
// Function decorators ///////////////////////////////////////////////////////// | |
export const not = fn => (...args) => !fn(...args) | |
export const maybe = fn => | |
(...args) => { | |
if (args.length < fn.length || args.some(arg => arg == null)) return | |
return fn(...args) | |
} | |
export const once = fn => { | |
var done = false | |
return (...args) => { | |
if (done) return | |
done = true | |
fn(...args) | |
} | |
} | |
export const curry = fn => { | |
const arity = fn.length; | |
const curried = (...args) => | |
args.length < arity ? (...more) => curried(...args, ...more) : fn(...args) | |
return curried | |
} | |
export const pipeline = (...funcs) => | |
value => funcs.reduce((a, b) => b(a), value) |
This file contains hidden or 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
import test from 'ava' | |
import { | |
combine, | |
compact, | |
difference, | |
head, | |
initial, | |
intersection, | |
last, | |
sortedIndex, | |
tail, | |
union, | |
unique, | |
without, | |
getValues, | |
toMap, | |
min, | |
max, | |
sum, | |
product, | |
not, | |
maybe, | |
once, | |
curry, | |
pipeline | |
} from './functional' | |
// Array utils ///////////////////////////////////////////////////////////////// | |
test('combine', t => | |
t.deepEqual(combine(['foo'], ['bar', 'baz'], [1, 2]), ['foo', 'bar', 'baz', 1, 2]) | |
) | |
test('compact', t => | |
t.deepEqual(compact([0, 1, false, 2, '', 3]), [1, 2, 3]) | |
) | |
test('difference', t => | |
t.deepEqual(difference([1, 2, 3, 4, 5], [5, 2, 10]), [1, 3, 4]) | |
) | |
test('head', t => | |
t.deepEqual(head(['foo', 'bar']), 'foo') | |
) | |
test('initial', t => | |
t.deepEqual(initial([3, 2, 1]), [3, 2]) | |
) | |
test('intersection', t => | |
t.deepEqual(intersection([1, 2, 3], [101, 2, 1, 10], [2, 1]), [1, 2]) | |
) | |
test('last', t => | |
t.deepEqual(last(['foo', 'bar' ]), 'bar') | |
) | |
test('sortedIndex', t => | |
t.deepEqual(sortedIndex([10, 20, 30, 40, 50], 35), 3) | |
) | |
test('tail', t => | |
t.deepEqual(tail(['foo', 'bar', 'baz']), ['bar', 'baz']) | |
) | |
test('union', t => | |
t.deepEqual(union([1, 2, 3], [101, 2, 1, 10], [2, 1]), [1, 2, 3, 101, 10]) | |
) | |
test('unique', t => | |
t.deepEqual(unique([1, 2, 1, 3, 1, 4]), [1, 2, 3, 4]) | |
) | |
test('without', t => | |
t.deepEqual(without([1, 2, 1, 0, 3, 1, 4], 0, 1), [2, 3, 4]) | |
) | |
// Object utils //////////////////////////////////////////////////////////////// | |
test('getValues', t => | |
t.deepEqual(getValues({ foo: 'bar', hello: 'world' }), ['bar', 'world']) | |
) | |
// ToDo: toMap | |
// test('toMap', t => {}) | |
// Math //////////////////////////////////////////////////////////////////////// | |
test('min', t => | |
t.deepEqual(min([10, 50, 30]), 10) | |
) | |
test('max', t => | |
t.deepEqual(max([10, 50, 30]), 50) | |
) | |
test('sum', t => | |
t.deepEqual(sum([10, 50, 30]), 90) | |
) | |
test('product', t => | |
t.deepEqual(product([10, 50, 30]), 15000) | |
) | |
// Function decorators ///////////////////////////////////////////////////////// | |
test('not', t => { | |
const isNull = x => x == null | |
const isSet = not(isNull) | |
t.deepEqual(isSet(undefined), false) | |
}) | |
// ToDo: maybe | |
// test('maybe', t => {}) | |
// ToDo: once | |
// test('once', t => {}) | |
test('curry', t => { | |
const add = curry((a, b) => a + b) | |
t.deepEqual(add(2, 3), 5) | |
t.deepEqual(add(2)(3), 5) | |
}) | |
test('pipeline', t => { | |
const plus1 = a => a + 1 | |
const mult2 = a => a * 2 | |
let addThenMult = pipeline(plus1, mult2) | |
t.deepEqual(addThenMult(5), 12) | |
}) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
combine(arrays)
Combine multiple arrays into one array.
compact(array)
Returns a copy of the array with all falsy values removed.
contains(array, value)
Returns true if the value is present in the array.
difference(array, others)
Similar to without, but returns the values from array that are not present in the other arrays.
head(array)
Returns the first element of an array.
initial(array)
Returns everything but the last entry of the array.
intersection(arrays)
Computes the list of values that are the intersection of all the arrays. Each value in the result is present in each of the arrays.
last(array)
Returns the last element of an array.
sortedIndex(array, value)
Determine the index at which the value should be inserted into the array in order to maintain the array's sorted order.
tail(array)
Returns everything but the first entry of the array.
toArray(arrayLike)
Returns a real Array. Useful for transmuting the arguments object.
union(arrays)
Computes the union of the passed-in arrays: the list of unique items, in order, that are present in one or more of the arrays.
unique(array)
Produces a duplicate-free version of the array.
without(array, values)
Returns a copy of the array with all instances of the values removed.
getValues(object)
Returns an array with the object's values.
merge(objects)
Combine multiple objects into a new object.
toMap(object)
Convert an Object to a Map.
min(array)
Returns the minimum value in the array.
max(array)
Returns the maximum value in the array.
sum(array)
Returns the sum of all values in the array.
product(array)
Returns the product of all values in the array.
not(function)
Creates a new function returning the opposite of the function provided as its argument.
maybe(function)
Returns a new function that won't execute if not enough arguments are provided.
once(function)
Returns a new function that won't execute more than once.
curry(function)
Curries a function.
pipeline(functions)
Returns the composition of multiple functions from left to right.