Reinventing the wheel with splitting arrays

Simon Taylor
5 min readMay 29, 2017

--

When I woke up this morning I had an amazing idea to create a better version array .filter! This idea was so genius it was almost inevitable that I would receive thousands upon thousands of github stars. The thought of this ludicrous power rushed to my head and I dived straight into creating this wonderful module.

The idea spawned from a pain point I had using .filter, often times you actually want to split an array into two using a function (or predicate as it’s sometimes called). When you use filter, you get only half the results (where true is returned) meaning if you want the other half you write a second filter function with the inverse conditional. This isn’t great because a) you need to loop through the array twice and b) because you might stuff up the logic when you inverse the conditional and drop elements. So then I thought…

Why not have a function that gives you both halves of the array in one loop! An array containing two arrays, one where the predicate returns true and one for false.

But wait it could be even better than that, what if the predicate instead returned a string, we could then return an object where it’s keys match the strings returned by the predicate, and the value contains an array of results for that key. This still lets us handle the true and false case, we just access either .true or .false property from the results object (it would stringify booleans for us).

But wait, there’s even more! Just imagine if you could also return null to drop records completely, so that they don’t appear in the results at all! This is genius level thinking right here.

So I bashed away at the keyboard for a fairly short amount of time and so array-split was born. I was so excited with that which I’d created. I was happy and ready to publish to npm but then I realised… F#@$!!! I’ve just re-written lodash .groupBy. Oh dear… I had done a cursory glance over lodash prior looking for things like .split, .segment, .divide but clearly hadn’t looked quite hard enough. To make matters worse I’ve actually used .groupBy before… god damn it…

After a brief period of disappointment I thought why not make something of this and write an article about it? .groupBy is actually a pretty rad function. So lets talk about some use cases for .groupBy and why it's so magical.

Lets talk first about what I mentioned earlier, splitting an array in half.

const groupBy = require('lodash/groupBy');const numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9];const predicate = (num) => {
if (num % 2 === 0) return 'even';
return 'odd';
}
const result = groupBy(numbers, predicate);

This gives us…

{
even: [2, 4, 6, 8],
odd: [1, 3, 5, 7, 9]
}

That’s actually pretty nice. Well what about my amazeballs idea to drop elements from the results by returning null? Well it’s got that covered also, imagine I really hate multiples of three and want to banish them from the universe. Well then we change the predicate function to…

const predicate = (num) => {
if (num % 3 === 0) return null;
if (num % 2 === 0) return 'even';
return 'odd';
}

Now we get this result…

{
even: [2, 4, 8],
null: [3, 6, 9],
odd: [1, 5, 7]
}

Okay so this isn’t exactly the same as what I was thinking, it’s actually better. You can choose to completely ignore the null values or you can still do something with them, it’s over to you. The predicate function actually supports any return type you want, strings, numbers, null, undefined and even objects (for some reason?), it will just convert it to a string so it can be used as a key in the result object. In summary though, you can not only split (group) your arrays, you can also effectively filter them at the same time.

So at this point you’re probably thinking .groupBy is pretty great and it is. I’m not going to be world famous for having re-invented the wheel, but that’s OK as there is so much amazing code out there for free which lets you just get on with the task at hand. Another lesson learned here is it’s well worth learning the functions lodash provides as there’s so much gold in there (see alsoflatMap below). So remember kids, use .groupBy and if you need a utility function, its probably already in lodash but it might not be named as you might expect. Thanks for reading.

You can find my failed experiment here and also on npm.

As a bonus I read a great article about flatMap recently which I now seem to be unable to find, so I thought I’d cover it quickly. flatMap is quite similar to map, except the predicate expects an array to be returned. If the array contains values (.length > 0) these are added to the resulting array. If the array contains no values (.length === 0), nothing is added to the results array.

Why is this great? It lets you effectively filter and map at the same time. For example lets get the full name of all the cool kids…

const flatMap = require('lodash/flatMap');// sorry, Simpsons is all I got right now...
const test = [
{ first: 'Bart', last: 'Simpson', cool: true },
{ first: 'Ralph', last: 'Wiggum', cool: false },
{ first: 'Milhouse', last: 'an Houten', cool: false },
{ first: 'Nelson', last: 'Muntz', cool: true },
];
const result = flatMap(test, character => {
if (!character.cool) return [];
return [`${character.first} ${character.last}`];
});

This then gives us…

["Bart Simpson", "Nelson Muntz"]

It could be argued that this is actually a terrible idea, in that it is simpler to reason about what’s happening when you perform two passes (one with map and one with filter) but I think it’s still good to have this in your arsenal.

--

--