18 Aug, 2013

I often find myself needing a function like `map`

or `filter`

, but unable/unwilling to import an entire library like the famous Lodash or Underscore (whichever you fancy). There can be many reasons for this, but my primary reason is usually that I am building a small plugin to handle some operation for someone, and it is entirely unreasonable of me to expect a client to important an entire library, five times the size of my little plugin, just so I can filter an array properly (or whatever else I need that library for).

So I often have to cherry pick functions from those libraries, but they are not built in a modular way internally. Functions inside the library are highly dependent on other functions in order to save bytes and speed. For instance you can't copy `map`

over without also copying `each`

. So instead, here are some functions that I wrote, that can all (save a few very obvious ones) be exported "as is" into other code. Change them, rename them, make them faster, do whatever you want with them. They are just a starting point, and a small building block for bigger things.

For this reason, I haven't added this "project" (seriously, it's just a file of code) to Bower or any some such. It's not meant to be included as a full library (if that's what you need, then use another library), but just some code that you can search through and copy/paste the stuff you need, and pretend you wrote it yourself.

**Important:** Since this is *not* a library meant to be included in any project as is, I will (most likely) at any point in time move things around, change implementations and/or functionality, and even names of functions.

*Aug 21:*All functions that take two arguments (that's most of them) are now curried by default. The docs below does not reflect this

We all love examples. Here are some of how this is meant to be used.

I consider `compose`

and `autoCurry`

(which is dependent on `curry`

) to be cornerstones in coding, and would include them in any project. Example 2 and 3 below reflect usage of them. As examples often are, these are a bit contrived.

Writing a small plugin, you need a function that flattens a list of lists. You know how to do this... sorta... but it'd be nice if someone else had already done it. So you find it in here and copy/paste it into your own project. No sweat.

var flatten = function(xs) { /* find the code in cherries.js ... */ };

And now you're flattening arrays all day long!

Let's find the average age of a list of people that looks like this:

var people = [ {name: 'Bob Roberts', age: 31, gender: 'm'}, {name: 'Julia Smith', age: 63, gender: 'f'}, {name: 'Ken Paulsen', age: 23, gender: 'm'}, {name: 'Lisa Erikson', age: 9, gender: 'f'} ];

For this, we could use `pluck`

and `mean`

.

/* I assume compose and autoCurry is already available */ var pluck = autoCurry( /* code defining pluck */ ), mean = /* code defining mean */;

And we compose the function we need,

Notice that since `pluck`

is autoCurried, calling it with just one argument (it needs two) will return a function waiting for a list of objects (how convenient) that returns a list of whatever we plucked out (in this case the age).

// Compose a function that first plucks out the age into a list, and then // takes the mean of that list var getMeanOfAges = compose( mean, pluck('age') ); // Try out our function getMeanOfAges(people) // 31.5

Of course, if you only need `pluck`

once, and to do only the above, then you'd probably not include `autoCurry`

and `pluck`

, but rather just define your own function and use that instead. Something like this:

// Quick adaptation of the `pluck` within cherries var pluckAge = function(xs){ var result = [], i = -1, len = xs.length; while (++i < len) { result.push(xs[i].age) } return result; }; var getMeanOfAges = compose(mean, pluckAge);

You're writing a little plugin for a client and you need an easy way to pull some data representing people out that comes in a list form, you want an object, and you want to pick out certain data.

Here's a sample list we could get from a server or whatever.

var people = [ ['Bob Roberts', 31, 'm'], ['Julia Smith', 63, 'f'], ['Ken Paulsen', 23, 'm'], ['Lisa Erikson', 9, 'f'] ];

First you pick out the functions you need from this library and define them using `autoCurry`

/* compose and autoCurry assumed */ var pick = autoCurry( /* code defining pick */ ), map = autoCurry( /* code defining map */ ), listsToObj = autoCurry( /* code defining listsToObj */ );

Then we build a function that turns `people`

into an object and gives us a list of of whatever we need

Like in the previous example, the functions are autoCurried, so calling them with less arguments than they expect (`map`

, `pick`

, and `listsToObj`

each need two arguments, we're calling them with one) means we get a function back that is waiting for the last argument.

var getNameAndAgeOf = compose( map( pick(['name', 'age']) ), map( listsToObj(['name', 'age', 'gender']) ) );

Calling this function on `people`

...

getNameAndAgeOf(people) // [{"name":"Bob Roberts","age":31}, ... ]

We can make it a bit more general use actually...

var getThisOfThat = function(xs) { return compose( map( pick(xs) ), map( listsToObj(['name', 'age', 'gender']) ) ); }; // Make a function that pulls out name and gender var getNameAndGender = getThisOfThat(['name', 'gender']) // Try out our new function getNameAndGender(people) // [{"name":"Bob Roberts","gender":"m"}, ... ]

See the examples at `lt`

for some more examples of usage.

Here's a list of each of the functions currently defined. Remember, **dig into the code and pull out the bits you need**. Don't just import everything; there are better libraries for that.

Jump to: id, isType, replicate, dot, pluck, each, map, filter, reject, partition, find, head, tail, last, initial, take, drop, takeWhile, dropWhile, span, breakList, empty, reverse, foldl, foldr, concat, flatten, any, all, sort, sortBy, sum, product, even, odd, lt, gt, eq, lteq, gteq, mean, maximum, minimum, zip, zipWith, keys, values, pairsToObj, objToPairs, listsToObj, objToLists, extend, extendAll, pick, omit, compose, curry, autoCurry.

`id`

, kind of does nothing.
a → a
id('foo') // 'foo' id([]) // []

`isType`

. You can check if a variable has a certain type with this.
"a" → a → Boolean
isType('Undefined', undefined) // true isType('Boolean', false) // true isType('Number', 3) // true isType('String', 'foo') // true isType('Object', {}) // true isType('Array', []) // true

`replicate`

. Creates an array with however many items of whatever you want.
Number → a → [a]
replicate(3, 'foo') // ['foo', 'foo', 'foo'] replicate(2, true) // [true, true]

`dot`

. Gets a property of the passed in object.
"a" → {a:b} → b
dot('age', {name: 'Simon', age: 45}) // 45 dot('status', {status: false}) // false

`pluck`

. Does the same as `dot`

, but for an array of objects.
"a" → [{a:b}] → [b]
pluck('age', [{name: 'Simon', age: 45}, {name: 'Bob', age: 12}]) // [45, 12] pluck('status', [{status: false}]) // [false]

`each`

. Your general `each`

or `forEach`

function. Nothing spectacular.
Notice, that as it is, it will default to the browser's native `forEach`

if it exists, in which case it will return `undefined`

and not the array you passed in.
Function → a → a
each(alert, [1, 2, 3]) // will call alert on each number each(alert, {one: 1, two: 2}) // once more :(

`map`

. A map function. Like `each`

it works on both arrays and objects (their values).
Function → a → a
map(function(x){ return x+1 }, [1, 2, 3]) // [2, 3, 4] map(function(x){ return x+1 }, {one: 1, two: 2}) // {one: 2, two: 3}

`filter`

.
Function → a → a
function even(x) { return x%2 === 0 } filter(even, [1, 2, 3, 4]) // [2, 4] filter(even, {one: 1, two: 2, three: 3}) // {two: 2}

`reject`

. Opposite `filter`

.
Function → a → a
reject(even, [1, 2, 3, 4]) // [1, 3] reject(even, {one: 1, two: 2, three: 3}) // {one: 1, three: 3}

`partition`

. Kind of like `filter`

and `reject`

in one. It returns an array with two items: first one of filtered items, second of reject items.
Fucntion → a → [a, a]
partition(even, [1, 2, 3, 4]) // [[2, 4], [1, 3]] partition(even, {one: 1, two: 2, three: 3}) // [{two: 2}, {one: 1, three: 3}]

`find`

. Finds the first value that matches your function and returns that.
Function → a → a
find(even, [1, 2, 3, 4]) // 2 find(even, {one: 1, two: 2, three: 3}) // 2

`head`

. Returns the "head" or first value of a list.
[a] → a
head([1, 2, 3, 4]) // 1

`tail`

. Returns the "tail" or everything but first value of a list.
[a] → [a]
tail([1, 2, 3, 4]) // [2, 3, 4]

`last`

. Returns the "last" or last value of a list.
[a] → a
last([1, 2, 3, 4]) // 4

`initial`

. Returns the "initial" part of a list, or everything but the last value.
[a] → a
initial([1, 2, 3, 4]) // [1, 2, 3]

`take`

. Takes `n`

number of values from a list.
Number → [a] → [a]
take(2, [1, 2, 3, 4]) // [1, 2]

`drop`

. Drops `n`

number of values from a list and returns the rest.
Number → [a] → [a]
drop(2, [1, 2, 3, 4]) // [3, 4]

`takeWhile`

. Copies your array until the values no longer returns truthy from your applied function.
Function → [a] → [a]
takeWhile(even, [2, 4, 0, 3, 4, 2]) // [2, 4, 0]

`dropWhile`

. Drops the values of a list until they no longer return truthy from your function. From that, it copies your array.
Function → [a] → [a]
dropWhile(even, [2, 4, 0, 3, 4, 2]) // [3, 4, 2]

`span`

is to `takeWhile`

and `dropWhile`

what `partition`

is to `filter`

and `reject`

.
Function → [a] → [[a], [a]]
span(even, [2, 4, 0, 3, 4, 2]) // [[2, 4, 0], [3, 4, 2]]

`breakList`

breaks a list into two where the function returns truthy.
Function → [a] → [[a], [a]]
breakList(even, [1, 3, 2, 4, 0, 3]) // [[1, 3], [2, 4, 0, 3]]

`empty`

checks if an array or object is empty.
a → Boolean
empty([]) // true empty({}) // true empty({one: 1}) // false

`reverse`

returns a reversed shallow copy of the list.
[a] → [a]
reverse([1, 2, 3]) // [3, 2, 1]

`foldl`

is your standard `reduce`

function.
Function → a → [a] → a
function add(x, y) { return x + y } foldl(add, 7, [1, 2, 3]) // 13

`foldr`

is your standard `reduceRight`

function.
Function → a → [a] → a
function subtract(x, y) { return x - y } foldl(subtract, 7, [1, 2, 3]) // 1

`concat`

takes a list of lists and concatenates them. Notice it only does this one level down.
[[a],[a]] → [a, a]
concat([[1, 2, 3], ['a', 'b']]) // [1, 2, 3, 'a', 'b']

`flatten`

takes a list of lists and flattens them.
[[a]] → [a]
flatten([ 1, [ [2], 3 ], [4, [[5]]], [{one: 1}, "hello"] ]) // [1, 2, 3, 4, 5, {one: 1}, "hello"]

`any`

can tell you if any values in a list returns truthy from a function.
Function → [a] → Boolean
any(even, [1, 2, 3]) // true any(even, [1, 3, 77]) // false

`all`

can tell you if all values in a list returns truthy from a function.
Function → [a] → Boolean
all(even, [1, 2, 3]) // false all(odd, [1, 3, 77]) // true

`sort`

sorts an array of numbers. (Have a look at the implementation, it is highly subjective what you will expect this to do).
[Number] → [Number]
sort([2, 12, 1]) // [1, 2, 12]

`sortBy`

sorts an array according to a provided function.
Function → [a] → [a]
sortBy(function(a, b) { return b-a }, [2, 12, 1]) // [12, 2, 1]

`sum`

. Sums up numbers in an array.
[Number] → Number
sum([3, 4, 5]) // 12

`product`

.
[Number] → Number
product([3, 4, 5]) // 60

`even`

. Checks if a number is even.
Number → Boolean
even(2) // true

`odd`

. Checks if a number is odd.
Number → Boolean
odd(3) // true

`lt`

. "Less than". Notice that the arguments are in "reversed" order so they make more sense when curried.
Number → Number → Boolean
lt(3, 2) // true // Curried var lt3 = curry(lt, 3); lt3(2) // true filter(lt3, [1, 5, 3, 9, 0, 2, 4, 2]) // [1, 0, 2, 2] // Or better yet, redefine `lt` with autoCurry for better reuse lt = autoCurry(lt); listOfNum = [1, 5, 3, 9, 0, 2, 4, 2]; // Just because we will need it filter(lt(3), listOfNum) // [1, 0, 2, 2] filter(lt(5), listOfNum) // [1, 3, 0, 2, 4, 2] // Let's go crazy var filterLt = autoCurry(function(n, xs) { return filter(lt(n), xs); // assuming `lt` is still autoCurried }); // Here we call `filterLt` twice with one argument each filterLt(3)(listOfNum) // [1, 0, 2, 2] // Here we call `filterLt` once with two arguments filterLt(5, listOfNum) // [1, 3, 0, 2, 4, 2]

`gt`

. "Greater than"
Number → Number → Boolean
gt(3,4) // true

`eq`

. "Equal" (This actually compares any two values using `===`

)
Number → Number → Boolean
eq(3,3) // true

`lteq`

. "Less than, Equal" or `<=`

Number → Number → Boolean
lteq(3,2) // true

`gteq`

. "Greather than, Equal" or `>=`

Number → Number → Boolean
gteq(3,3) // true

`mean`

. Finds the mean of the numbers in a list.
[Number] → Number
mean([1, 2, 3, 4]) // 2.5

`maximum`

finds the highest number in a list.
[Number] → Number
maximum([6, 7, 2, 3]) // 7

`minimum`

finds the lowest number in a list.
[Number] → Number
minimum([6, 7, 2, 3]) // 2

`zip`

takes two arrays and "zips" them together.
[a] → [b] → [[a, b]]
zip(['a', 'b', 'c'], [1, 2, 3]) // [['a', 1], ['b', 2], ['c', 3]]

`zipWith`

takes a function and two arrays and zips them together using that function.
Function → [a] → [a] → [a]
function add(x, y) { return x+y } zipWith( add, [1, 2, 3], [7, 8, 9]) // [8, 10, 12]

`keys`

returns an array with the keys of an object.
{a:b} → [a]
keys({one: 1, two: 2, three: 3}) // ['one', 'two', 'three']

`values`

returns an array with the values of an object.
{a:b} → [b]
values({one: 1, two: 2, three: 3}) // [1, 2, 3]

`pairsToObj`

. Takes an array of arrays with two values and turns them into an object.
[[a, b]] → {a:b}
pairsToObj([['a', 1], ['b', 2], ['c', 3]]) // {a: 1, b: 2, c: 3}

`objToPairs`

does the opposite as above.
{a:b} → [[a, b]]
objToPairs({a: 1, b: 2, c: 3}) // [['a', 1], ['b', 2], ['c', 3]]

`listsToObj`

takes two lists and returns an object with one arrays' values as keys and the other as the values.
[a] → [b] → {a:b}
listsToObj(['a', 'b', 'c'], [1, 2, 3]) // {a: 1, b: 2, c: 3}

`objToLists`

does the opposite as above.
{a:b} → [[a], [b]]
objToLists({a: 1, b: 2, c: 3}) // [['a', 'b', 'c'], [1, 2, 3]]

`extend`

takes two objects and "extends" them to a shallow clone.
Because it takes a fixed number of arguments, it is easy to curry, whereas `extendAll`

is a bit tricky.
{a} → {a} → {a}
extend({one: 1, two: 2, three: 3}, {three: 33, four: 44}) // {one: 1, two: 2, three: 33, four: 44}

`extendAll`

takes two or more objects and returns one object with the keys and values from all the others. (The copy is shallow)
Because it takes a variable number of arguments, this function is a bit tricky to curry.
{a} → {a} → ... → {a}
extendAll({one: 1, two: 2, three: 3}, {three: 33, four: 44}, {four: 'f', five: 'g'}) // {one: 1, two: 2, three: 33, four: 'f', five: 'g'}

`pick`

returns an object with the keys you asked for.
[a] → {a} → {a}
pick(['one', 'three'], {one: 1, two: 2, three: 3}) // {one: 1, three: 3}

`omit`

. Opposite `pick`

.
[a] → {a} → {a}
omit(['one', 'three'], {one: 1, two: 2, three: 3}) // {two: 2}

`compose`

. Composes functions together. Takes an optional number of arguments, so this can't be curried.
Perhaps ironically, this function becomes a lot more powerful when other functions are curried.
Function → Function → ... → Function
function getName(o) { return o['name'] } var alertName = compose(alert, getName) alertName({name: 'Simon', age: 45}) // alerts 'Simon' // If `dot` is autoCurried (dot = autoCurry(dot);) then var alertName2 = compose(alert, dot('name')); alertName2({name: 'Simon', age: 45}) // alerts 'Simon'

`curry`

. Returns a curried version of a function. This is not really meant to be used as is, but rather `autoCurry`

is dependent on it.
Function → a → ... → Function
function add(x, y) { return x+y } var add1 = curry(add, 1) add1(2) // 3 add1(5) // 6

`autoCurry`

. Takes a function and an optional number, and returns a curried version of that function. The number, if applied, tells `autoCurry`

how many arguments it needs to be fully applied. (if not applied it will deduct it using `fn.length`

.
I personally define almost all my function inside this function.
Function → (Number →) Function
var cAdder = autoCurry( function(x, y) { return x+y } ); var add1 = cAdder(1); add1(2) // 3 add1(5) // 6 var add5 = cAdder(5); add5(2) // 7 add5(5) // 10

`applyl`

. Takes a function and a list of arguments, and returns a function that waits for the last arguments. This function is a bit like `curry`

, except curry will wait for all arguments to arrive, while this will run the function next time called, no matter what
Function → [a] → Function
var calc = function(x, y, z) { return (x+y)*z }; var times3 = applyl(calc, [1, 2]); times3(4) // 12 times3(7) // 21 times3() // NaN var isBool = applyl(isType, ['Boolean']); isBool(false) // true isBool('Hello') // false

`applyr`

. Takes a function and a list of arguments, and returns a function that waits for the "first" arguments.
Function → [a] → Function
var calc = function(x, y, z) { return (x+y)*z }; var add1AndMultiplyBy2 = applyr(calc, [1, 2]); add1AndMultiplyBy2(3) // 8 add1AndMultiplyBy2(21) // 44