2019-07-23
|~3 min read
|450 words
I came across a situation where I had a collection of collections. Some of the internal collections, however, I didn’t want to keep around because of the values it held. If all of the values resolved to false
, I would throw it out - but if even a single one was truthy, I’d keep it around.
I needed a way to economically filter them out. If I was dealing with arrays, I’d use .reduce
and .some
. Faced with objects, however, I looked to Lodash’s methods for both — which conveniently handle not only arrays, but all collections (which includes objects).
NB: The following example is contrived, but illustrative of the kind of situation I was facing.
const init = {
first: {
title: "first",
names: {
a: true,
b: false,
c: true,
},
},
second: {
title: "second",
names: {
d: false,
e: false,
f: false,
},
},
}
So, passing the init
through a function, we’ll call it clean
, I want to see the following object:
const output = {
first: {
title: "first",
names: {
a: true,
b: false,
c: true,
},
},
}
Lodash’s some
method fit my use case well. I wanted an escape hatch as quickly as possible if I found a true value
My first step was understanding how to use the _.some
. The documentation paints the picture:
Checks if
predicate
returns truthy foranyelement ofcollection
. Iteration is stopped oncepredicate
returns truthy. The predicate is invoked with three arguments: (value, index|key, collection).
Unfortunately, while it’s clear that this is possible, the examples don’t show how it’s used, focusing more on the magic that Lodash enables.
Here’s a simple example of _.some
in practice given our init
object:
function checkSome(collection) {
return _.some(collection.names, (val, key, collection) => {
return val
})
}
console.log(checkSome(init.first)) // true
console.log(checkSome(init.school)) // false
Okay, so that’s the second step — but, how do I actually get to it? With the _.reduce
.
A reminder on how the _.reduce
works:
Reduces
collection
to a value which is the accumulated result of running each element incollection
thruiteratee
, where each successive invocation is supplied the return value of the previous. Ifaccumulator
is not given, the first element ofcollection
is used as the initial value. The iteratee is invoked with four arguments: (accumulator, value, index|key, collection).
function reducer(accumulator, value, key, collection) {
// if some of the values return true when passed into checkSome
if (checkSome(value)) {
// add them to the accumulator
accumulator[key] = value
}
return accumulator
}
function clean(collection) {
return _.reduce(collection, reducer, {})
}
const reducedInit = clean(init)
Voila! My reducedInit
returns only the desired values.
Hi there and thanks for reading! My name's Stephen. I live in Chicago with my wife, Kate, and dog, Finn. Want more? See about and get in touch!