You are currently viewing How can I group and count values in a JavaScript array?

How can I group and count values in a JavaScript array?

Spread the love

How can I group and count values in a JavaScript array?

Finding theĀ count of each value in an array can come in handy in a lot of situations. It’s also fairly straightforward to implement, both for primitive and complex values, using JavaScript’s Array methods.

tropical waterfall 1200

Count the occurrences of each value in an array

You can useĀ Array.prototype.reduce()Ā to create an object with the unique values of an array as keys and theirĀ frequenciesĀ as the values. Use the nullish coalescing operator (??) to initialize the value of each key toĀ 0Ā if it doesn’t exist and increment it byĀ 1 every time the same value is encountered.

const countOccurrences = array =>

array.reduce((accumulator, currentValue) => {
accumulator[currentValue] = (accumulator[currentValue] ?? 0) + 1;
return accumulator;
}, {});
console.log(countOccurrences(['a', 'b', 'a', 'c', 'a', 'a', 'b']));
// Output: { a: 4, b: 2, c: 1 }

console.log(countOccurrences([...'ball']));

// Output: { b: 1, a: 1, l: 2 }

Code Breakdown:

  1. arr.reduce(): This method iterates over the array, applying a function to each element and accumulating a result, which is an object in this case.
  2. a[v] = (a[v] ?? 0) + 1;:
    • a[v]: This is the key in the object a corresponding to the value v in the array.
    • ?? 0: The nullish coalescing operator checks if a[v] is null or undefined. If it is, it initializes it to 0. Otherwise, it keeps its current value.
    • + 1: The value is then incremented by 1, counting the occurrence.
  3. return a;: The final result is the object a that has all unique array elements as keys with their corresponding counts as values.
  4. frequencies([...array]): This function can be applied to any array to get the frequency of each element in that array.

Example Usage:

  • frequencies(['a', 'b', 'a', 'c', 'a', 'a', 'b']);
    • The result will be { a: 4, b: 2, c: 1 } because ‘a’ appears 4 times, ‘b’ appears 2 times, and ‘c’ appears once.
  • frequencies([...'ball']);
    • This spreads the string “ball” into an array ['b', 'a', 'l', 'l'].
    • The result will be { b: 1, a: 1, l: 2 } because ‘b’ and ‘a’ appear once, and ‘l’ appears twice.

This function is a concise way to count occurrences of elements in an array, leveraging modern JavaScript features like reduce() and the nullish coalescing operator.

Group the elements of an array based on a function

You can alsoĀ group the elementsĀ of an array based on a given function and return the count of elements in each group. This can be useful when you want to group elements based on a specific property or a function.

To do so, you can useĀ Array.prototype.map()Ā toĀ map the valuesĀ of an array to a function or property name, and then useĀ Array.prototype.reduce() to create an object, where the keys are produced from the mapped results.

const countBy = (array, iteratee) =>
array
.map(item => typeof iteratee === 'function' ? iteratee(item) : item[iteratee])
.reduce((accumulator, value) => {
accumulator[value] = (accumulator[value] || 0) + 1;
return accumulator;
}, {});
// Example usage:

console.log(countBy([6.1, 4.2, 6.3], Math.floor));

// Output: { 4: 1, 6: 2 }

console.log(countBy(['one', 'two', 'three'], 'length'));

// Output: { 3: 2, 5: 1 }
console.log(countBy([{ count: 5 }, { count: 10 }, { count: 5 }], x => x.count));
// Output: { 5: 2, 10: 1 }

Explanation:

1. Function Name and Parameters:

  • countBy: The function is named countBy to indicate that it counts items in an array based on a specific criterion.
  • array: This is the input array whose items you want to count.
  • iteratee: This is either a function or a string representing a property name. It determines how the items in the array should be transformed before counting.

2. Mapping the Array:

  • map(item => typeof iteratee === 'function' ? iteratee(item) : item[iteratee]):
    • If iteratee is a function, it is applied to each item in the array to transform it.
    • If iteratee is a string, it is treated as a property name, and the corresponding property value is extracted from each item.

3. Reducing the Array:

  • reduce((accumulator, value) => { ... }):
    • accumulator[value] = (accumulator[value] || 0) + 1;: This line counts how many times each transformed value appears in the array.
    • If the value has already been encountered, it increments the count. If not, it initializes the count to 1.
  • The final result is an object (accumulator) that contains the counts of each unique transformed value.

4. Example Usage:

  • countBy([6.1, 4.2, 6.3], Math.floor);
    • This uses Math.floor to round down each number in the array, resulting in { 4: 1, 6: 2 }.
  • countBy(['one', 'two', 'three'], 'length');
    • This counts the number of strings with the same length, resulting in { 3: 2, 5: 1 }.
  • countBy([{ count: 5 }, { count: 10 }, { count: 5 }], x => x.count);
    • This counts the occurrences of the count property, resulting in { 5: 2, 10: 1 }.

Using aĀ MapĀ instead of an object

Both of the previous examples useĀ objectsĀ to store the frequencies of the values. However, you can also use aĀ MapĀ to store the frequencies. This can be useful if you need toĀ keep the insertion orderĀ of the keys or if you need toĀ iterate over the keysĀ in the order they were inserted. It’s also more efficient when you need toĀ delete keysĀ orĀ check for the existence of a key.

// Function to calculate the frequency of elements in an array
const frequenciesMap = (arr) => {
return arr.reduce((map, value) => {
map.set(value, (map.get(value) ?? 0) + 1);
return map;
},
new Map());
};
// Example usage of frequenciesMap
const frequencyResult = frequenciesMap(['a', 'b', 'a', 'c', 'a', 'a', 'b']);
console.log(frequencyResult); // Output: Map(3) { 'a' => 4, 'b' => 2, 'c' => 1 }
// Function to count elements based on a given function or property
const countByMap = (arr, fn) => {
return arr
.map(typeof fn === 'function' ? fn : value => value[fn])
.reduce((map, value) => {
map.set(value, (map.get(value) || 0) + 1);
return map;
}, new Map());
};
// Example usage of countByMap
const countByFloor = countByMap([6.1, 4.2, 6.3], Math.floor);
console.log(countByFloor); // Output: Map(2) { 6 => 2, 4 => 1 }
const countByLength = countByMap(['one', 'two', 'three'], 'length');
console.log(countByLength); // Output: Map(2) { 3 => 2, 5 => 1 }
const countByCount = countByMap([{ count: 5 }, { count: 10 }, { count: 5 }], item => item.count);
console.log(countByCount); // Output: Map(2) { 5 => 2, 10 => 1 }

To efficiently manage and update the frequencies of elements, you can design a custom data structure known as a frequency map. This data structure will allow you to quickly check, increment, and decrement the frequency of values. Here’s a step-by-step guide to implementing this frequency map:

Frequency Map Data Structure

Overview

A frequency map is essentially a specialized dictionary where the keys are the elements whose frequencies are being tracked, and the values are the counts of those elements.

Features

  1. Add Element: Increment the frequency of an element.
  2. Remove Element: Decrement the frequency of an element.
  3. Get Frequency: Retrieve the current frequency of an element.
  4. Check Existence: Determine if an element is present in the map.

class FrequencyMap extends Map {
constructor(iterable) {
super();
if (iterable) {
for (const value of iterable) {
this.increment(value);
}
}
}
get(value) {
return super.get(value) ?? 0;
}
has(value) {
return this.get(value) > 0;
}
increment(value) {
super.set(value, this.get(value) + 1);
return this;
}
decrement(value) {
const currentValue = this.get(value);
if (currentValue > 0) {
super.set(value, currentValue - 1);
}
return this;
}
toSortedArray(ascending = true) {
const sortedEntries = [...this].sort((a, b) => {
const comparison = a[1] - b[1];
return ascending ? comparison : -comparison;
});
return sortedEntries.map(entry => entry[0]);
}
}
// Example usage
const fMap = new FrequencyMap(['a', 'b', 'c', 'a', 'a', 'b']);
fMap.decrement('c')
fMap.increment('d');
console.log(fMap.toSortedArray(false)); // [ 'a', 'b', 'd' ]

Key Changes:

  1. Initialization Check: Added a check to ensure the iterable is defined before using it.
  2. Decrement Logic: Simplified the decrement method to avoid negative values and ensure values are properly handled.
  3. Sorting Function: Improved the toSortedArray method to handle ascending and descending sorting based on the ascending parameter.
  4. Code Cleanliness: Improved readability and consistency in code style.

techbloggerworld.com

šŸ’» Tech l Career l startup l Developer| Job šŸ“Bangalore, KA šŸ“© work: n4narendrakr@gmail.com šŸŽ“ Ex-SDE intern at Airtel

Leave a Reply