10 More Utility Functions Made with Reduce
By Yazeed Bzadough
This time, with a test suite!
Previously I wrote about 10 utility functions implemented with JavaScript's reduce function. It was well-received, and I walked away with an even deeper appreciation for this magnificent multi-tool. Why not try 10 more?
Many of these were inspired by the awesome libraries Lodash and Ramda! I also wrote unit tests to ensure correct behavior. You can see everything on the Github repo here.
1. pipe
Parameters
...functions
- Any number of functions.
Description
Performs left-to-right function composition. The first argument to a pipeline acts as the initial value, and is transformed as it passes through each function.
Implementation
const pipe = (...functions) => (initialValue) =>
functions.reduce((value, fn) => fn(value), initialValue);
Usage
const mathSequence = pipe(
(x) => x * 2,
(x) => x - 1,
(x) => x * 3
);
mathSequence(1); // 3
mathSequence(2); // 9
mathSequence(3); // 15
For more detail, I wrote an article on pipe here.
2. compose
Parameters
...functions
- Any number of functions.
Description
Performs right-to-left function composition. The first argument to a pipeline acts as the initial value, and is transformed as it passes through each function.
Works like pipe
, but in the opposite direction.
Implementation
const compose = (...functions) => (initialValue) =>
functions.reduceRight((value, fn) => fn(value), initialValue);
Usage
const mathSequence = compose(
(x) => x * 2,
(x) => x - 1,
(x) => x * 3
);
mathSequence(1); // 4
mathSequence(2); // 10
mathSequence(3); // 16
For more detail, I wrote an article on compose here.
3. zip
Parameters
list1
- List of items.list2
- List of items.
Description
Pairs items from two lists via index. If list lengths are not equal, the shorter list's length is used.
Implementation
const zip = (list1, list2) => {
const sourceList = list1.length > list2.length ? list2 : list1;
return sourceList.reduce((acc, _, index) => {
const value1 = list1[index];
const value2 = list2[index];
acc.push([value1, value2]);
return acc;
}, []);
};
Usage
zip([1, 3], [2, 4]); // [[1, 2], [3, 4]]
zip([1, 3, 5], [2, 4]); // [[1, 2], [3, 4]]
zip([1, 3], [2, 4, 5]); // [[1, 2], [3, 4]]
zip(['Decode', 'secret'], ['this', 'message!']);
// [['Decode', 'this'], ['secret', 'message!']]
4. intersperse
Parameters
separator
- Item to insert.list
- List of items.
Description
Inserts a separator between each element of a list.
Implementation
const intersperse = (separator, list) =>
list.reduce((acc, value, index) => {
if (index === list.length - 1) {
acc.push(value);
} else {
acc.push(value, separator);
}
return acc;
}, []);
Usage
intersperse('Batman', [1, 2, 3, 4, 5, 6]);
// [1, 'Batman', 2, 'Batman', 3, 'Batman', 4, 'Batman', 5, 'Batman', 6]
intersperse('Batman', []);
// []
5. insert
Parameters
index
- Index to insert element at.newItem
- Element to insert.list
- List of items.
Description
Inserts an element at the given index. If the index is too large, element is inserted at the end of the list.
Implementation
const insert = (index, newItem, list) => {
if (index > list.length - 1) {
return [...list, newItem];
}
return list.reduce((acc, value, sourceArrayIndex) => {
if (index === sourceArrayIndex) {
acc.push(newItem, value);
} else {
acc.push(value);
}
return acc;
}, []);
};
Usage
insert(0, 'Batman', [1, 2, 3]);
// ['Batman', 1, 2, 3]
insert(1, 'Batman', [1, 2, 3]);
// [1, 'Batman', 2, 3]
insert(2, ['Batman'], [1, 2, 3]);
// [1, 2, ['Batman'], 3]
insert(10, ['Batman'], [1, 2, 3]);
// [1, 2, 3, ['Batman']]
6. flatten
Parameters
list
- List of items.
Description
Flattens a list of items by one level.
Implementation
const flatten = (list) => list.reduce((acc, value) => acc.concat(value), []);
Usage
flatten([[1, 2], [3, 4]]);
// [1, 2, 3, 4]
flatten([[1, 2], [[3, 4]]]);
// [1, 2, [3, 4]]
flatten([[[1, 2]], [3, 4]]);
// [[1, 2], 3, 4]
flatten([[[1, 2], [3, 4]]]);
// [[1, 2], [3, 4]]
7. flatMap
Parameters
mappingFunction
- Function to run on each list item.list
- List of items.
Description
Maps each list item according to the given function, then flattens the result.
Implementation
// Kind of cheating, because we already implemented flatten ?
const flatMap = (mappingFunction, list) => flatten(list.map(mappingFunction));
Usage
flatMap((n) => [n * 2], [1, 2, 3, 4]);
// [2, 4, 6, 8]
flatMap((n) => [n, n], [1, 2, 3, 4]);
// [1, 1, 2, 2, 3, 3, 4, 4]
flatMap((s) => s.split(' '), ['flatMap', 'should be', 'mapFlat']);
// ['flatMap', 'should', 'be', 'mapFlat']
8. includes
Parameters
item
- Item to check the list for.list
- List of items.
Description
Checks a list for a given element. If the element is found, returns true
. Otherwise returns false
.
Implementation
const includes = (item, list) =>
list.reduce((isIncluded, value) => isIncluded || item === value, false);
Usage
includes(3, [1, 2, 3]); // true
includes(3, [1, 2]); // false
includes(0, []); // false
9. compact
Parameters
list
- List of items.
Description
Removes "falsey" values from a list.
Implementation
const compact = (list) =>
list.reduce((acc, value) => {
if (value) {
acc.push(value);
}
return acc;
}, []);
Usage
compact([0, null, 1, undefined, 2, '', 3, false, 4, NaN]);
// [1, 2, 3, 4]
10. arrayIntoObject
Parameters
key
- String to use as the new object key.list
- List of items.
Description
Converts an array into an object, using the given key as the new object's key.
Implementation
const arrayIntoObject = (key, list) =>
list.reduce((acc, obj) => {
const value = obj[key];
acc[value] = obj;
return acc;
}, {});
Usage
const users = [
{ username: 'JX01', status: 'offline' },
{ username: 'yazeedBee', status: 'online' }
];
arrayIntoObject('username', users);
/*
{
JX01: {
username: 'JX01',
status: 'offline'
},
yazeedBee: { username: 'yazeedBee', status: 'online' }
}
*/
arrayIntoObject('status', users);
/*
{
offline: {
username: 'JX01',
status: 'offline'
},
online: { username: 'yazeedBee', status: 'online' }
}
*/
Want Free Coaching?
If you'd like to schedule a free call to discuss Front-End development questions regarding code, interviews, career, or anything else follow me on Twitter and DM me.
After that if you enjoy our first meeting, we can discuss an ongoing coaching to help you reach your Front-End development goals!
Thanks for reading
For more content like this, check out https://yazeedb.com!
Until next time!
Subscribe to my newsletter
Read articles from freeCodeCamp directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by
freeCodeCamp
freeCodeCamp
Learn to code. Build projects. Earn certifications—All for free.