by Alex Permyakov
When you read about Array.reduce and how cool it is, the first and sometimes the only example you find is the sum of numbers. This is not our definition of ‘useful’. ?
Moreover, I’ve never seen it in a real codebase. But, what I’ve seen a lot is 7–8 line for-loop statements for solving a regular task where Array.reduce could do it in one line.
Recently I rewrote a few modules using these great functions. It surprised me how simplified the codebase became. So, below is a list of goodies.
If you have a good example of using a map or reduce method — post it in the comments section. ?
Let’s get started!
1. Remove duplicates from an array of numbers/strings
Well, this is the only one not about map/reduce/filter, but it’s so compact that it was hard not to put it in the list. Plus we’ll use it in a few examples too.
- Try it on CodePen. This code displays a bullet list of numbers between 1 and 5. Basic List Component. Usually you would render lists inside a component. We can refactor the previous example into a component that accepts an array of numbers and outputs a list of elements.
- The fill method changes all elements in an array to a static value, from a start index (default 0) to an end index (default array.length). It returns the modified array.
- Now I want a JSON format for Map Map in which Key should be Day and Value should be the Map having Key as Hours and Values as list of Hours which has same day. Something like this format.
2. A simple search (case-sensitive)
The filter() method creates a new array with all elements that pass the test implemented by the provided function.
3. A simple search (case-insensitive)
4. Check if any of the users have admin rights
The some() method tests whether at least one element in the array passes the test implemented by the provided function.
5. Flattening an array of arrays
The result of the first iteration is equal to : […, …[1, 2, 3]] means it transforms to [1, 2, 3] — this value we provide as an ‘acc’ on the second iteration and so on.
We can slightly improve this code by omitting an empty array
as the second argument for reduce(). Then the first value of the nested will be used as the initial acc value. Thanks to Vladimir Efanov.
Note that using the spread operator inside a reduce is not great for performance. This example is a case when measuring performance makes sense for your use-case. ☝️
Thanks to Paweł Wolak, here is a shorter way without Array.reduce:
Also Array.flat is coming, but it’s still an experimental feature.
6. Create an object that contains the frequency of the specified key
Let’s group and count the ‘age’ property for each item in the array:
Thanks to sai krishna for suggesting this one!
7. Indexing an array of objects (lookup table)
Instead of processing the whole array for finding a user by id, we can construct an object where the user’s id represents a key (with constant searching time).
It’s useful when you have to access your data by id like
uTable.name a lot.
8. Extract the unique values for the given key of each item in the array
Let’s create a list of existing users’ groups. The map() method creates a new array with the results of calling a provided function on every element in the calling array.
9. Object key-value map reversal
This one-liner looks quite tricky. We use the comma operator here, and it means we return the last value in parenthesis —
acc. Let’s rewrite this example in a more production-ready and performant way:
Here we don’t use spread operator — it creates a new array on each reduce() call, which leads to a big performance penalty: O(n²). Instead the old good push() method.
10. Create an array of Fahrenheit values from an array of Celsius values
Think of it as processing each element with a given formula ?
11. Encode an object into a query string
12. Print a table of users as a readable string only with specified keys
Sometimes you want to print your array of objects with selected keys as a string, but you realize that JSON.stringify is not that great ?
JSON.stringify can make the string output more readable, but not as a table:
13. Find and replace a key-value pair in an array of objects
Let’s say we want to change John’s age. If you know the index, you can write this line:
users.age = 29. However, let’s take a look at another way of doing it:
Here instead of changing the single item in our array, we create a new one with only one element different. Now we can compare our arrays just by reference like
updatedUsers users which is super quick! React.js uses this approach to speed up the reconciliation process. Here is an explanation.
14. Union (A ∪ B) of arrays
Less code than importing and calling the lodash method union.
15. Intersection (A ∩ B) of arrays
The last one!
As an exercise try to implement difference (A B) of the arrays. Hint: use an exclamation mark.
Thanks to Asmor and incarnatethegreat for their comments about #9.
If you have any questions or feedback, let me know in the comments down below or ping me on Twitter.
If this was useful, please click the clap ? button down below a few times to show your support! ⬇⬇ ??
Here are more articles I’ve written:
Production ready Node.js REST APIs Setup using TypeScript, PostgreSQL and Redis.
A month ago I was given a task to build a simple Search API. All It had to do is to grab some data from 3rd party…
Thanks for reading ❤️
Let’s step away from the individual data structures and talk about the iterations over them.
In the previous chapter we saw methods
These methods are generic, there is a common agreement to use them for data structures. If we ever create a data structure of our own, we should implement them too.
They are supported for:
Plain objects also support similar methods, but the syntax is a bit different.
Object.keys, values, entries
For plain objects, the following methods are available:
- Object.keys(obj) – returns an array of keys.
- Object.values(obj) – returns an array of values.
- Object.entries(obj) – returns an array of
Please note the distinctions (compared to map for example):
The first difference is that we have to call
Object.keys(obj), and not
data that implements its own
data.values() method. And we still can call
Object.values(data) on it.
The second difference is that
Object.* methods return “real” array objects, not just an iterable. That’s mainly for historical reasons.
Object.keys(user) = ['name', 'age']
Object.values(user) = ['John', 30]
Object.entries(user) = [ ['name','John'], ['age',30] ]
Here’s an example of using
Object.values to loop over property values:
Just like a
for..in loop, these methods ignore properties that use
Symbol(...) as keys.
Usually that’s convenient. But if we want symbolic keys too, then there’s a separate method Object.getOwnPropertySymbols that returns an array of only symbolic keys. Also, there exist a method Reflect.ownKeys(obj) that returns all keys.
Objects lack many methods that exist for arrays, e.g.
filter and others.
If we’d like to apply them, then we can use
Object.entries(obj)to get an array of key/value pairs from
- Use array methods on that array, e.g.
Object.fromEntries(array)on the resulting array to turn it back into an object.
For example, we have an object with prices, and would like to double them:
It may look difficult from the first sight, but becomes easy to understand after you use it once or twice. We can make powerful chains of transforms this way.