2

I have an array of objects with known keys. And I want to count how many objects have a particular key with a certain value. Currently I made it up with this:

counter = () => {
        if (Array) {
            let a = 0;
            for (let i = 0; i < Array.length; i++) {
                if (Array[i].key === '1' || Array[i].key === '2' || Array[i].key === '3' || Array[i].key === '4' || Array[i].key === '5' || Array[i].key === '6' || Array[i].key === '7') {
                    a++;
                }
            }
            return a;
        }
    }

I tried reduce() and find() while converting arrays to objects and vice versa but with no luck yet.
I suppose there should be more elegant way to perform such a simple task in plain vanilla JS ES6 or ES7. Ideally a oneliner. No lodashing please.

All other questions here target searching in elements, when mine touch one level deeper.

Igniter
  • 857
  • 9
  • 24

5 Answers5

2

You can try to use the javascript filter function: Something like:

var count = array.filter(function(e){
                  return (e.key === '1' || e.key === '2' || e.key === '3' || e.key === '4' || e.key === '5' || e.key === '6' || e.key === '7')

}).length;

Basically, this filter your array of objects by the keys you want, at the end it calculates the array length.

Pedro Simão
  • 283
  • 1
  • 11
1

Sure, here is that oneliner:

 array.reduce((count, el) => count + +["1", "2", "3", "4", "5", "6", "7"].includes(el.key), 0)

This uses includes to check wether el.key is one of the numbers, then the resulting boolean is turned into a number with the unary plus (true -> 1, false -> 0), and that is added to count for each element, resulting in the total count.

Jonas Wilms
  • 132,000
  • 20
  • 149
  • 151
1

You can do this with .filter() fairly easily, like so:

The idea is that you want to filter down to only the objects that match, and then use a .length to get the count at the end. We can know if an element matches by checking if the object's key property value is included in the list of keys you are searching for.

var test = [
{ key: '1' },
{ key: '3' },
{ key: '2' },
{ key: '7' },
{ key: '5' },
{ key: '8' },
]
var keysToSearch = ['1', '2', '3', '4', '5', '6', '7'];

function counter (objs, searchKeys) {
  return objs.filter(obj => searchKeys.includes(obj.key)).length;
}

console.log(counter(test, keysToSearch));

EDIT

Here's a solution that does the same thing as the above, but doesn't create a new array with .filter().

var test = [
{ key: '1' },
{ key: '3' },
{ key: '2' },
{ key: '7' },
{ key: '5' },
{ key: '8' },
]
var keysToSearch = ['1', '2', '3', '4', '5', '6', '7'];

function counter (objs, searchKeys) {
  var count = 0;
  for (var obj of objs) {
    if (searchKeys.includes(obj.key)) { count++; }
  }
  return count;
}

console.log(counter(test, keysToSearch));
mhodges
  • 10,938
  • 2
  • 28
  • 46
1

Try using

var count = b.filter(element => {return element.key == requiredKey;}).length;

count will have the number of objects with same key

Ranjith Eswaran
  • 333
  • 2
  • 12
0

Do not create new array, one line, loop on keys to reduce the loop iterations.

Reduce work like :

array.reduce((accumulator, oneArrayValue) => {
  // Function where treatment are done
  return theAccumulatorValueForNextLoopIteration;
}, initialValueOfTheAccumulator);

function counter(obj, keys) {
  // void 0 equals undefined
  // So it's equivalent to typeof x !== 'undefined'

  // tmp is the accumulator, it's value is setted up at 0
  // then it becomes what you return after every loop
  return keys.reduce((tmp, x) => obj[x] !== void 0 ? tmp + 1 : tmp, 0);
}

console.log(counter({
  1: 'hey',
  2: 'how',
  8: 'you',
  12: 'doing',
  15: 'baguette',
}, [
  '1',
  '2',
  '3',
  '4',
  '5',
  '6',
  '7',
]));
Orelsanpls
  • 22,456
  • 6
  • 42
  • 69