Get total of dynamic values in one array from another array


#1

I have an array

let options = ["Excellent","Very good","Good","Fair","Poor"];

and another array

let answers = [ 'Excellent', 'Excellent', 'Excellent', 'Very good', 'Excellent' ]

I would like to get the total for how many times an option was answered and my preferred output would be;

let totals = { "excellent": 4, "very good": 1, "good" :0, "fair": 0, "poor": 0 }

Another thing to note is that the options array is dynamic and not static, so it can consist of any value. Can someone please help me with a process to achieve this?


#2

Hi there habeebmaciver,

and a warm welcome to these forums. :winky:

Does this help…

<script>
(function() {
   'use strict';
   var options = ['Excellent', 'Very good', 'Good', 'Fair', 'Poor'],
       answers = [ 'Excellent', 'Excellent', 'Excellent', 'Very good', 'Excellent' ],
       totals = [], 
       count = 0;

    options.forEach( function( rateO ) {
       answers.forEach( function( rateA ) {
          if ( rateO === rateA ) {
               count ++; 
            }
         });

      totals.push( rateO + ': ' + count );
      count = 0;
 });
      console.log( totals )
}());
</script>

coothead


#3

I think that outputs an array of strings in the form ["key: value", "key: value"...], where instead you want an object in the form {key: value}. If the above didn’t work, another solution could be:

let options = ["Excellent","Very good","Good","Fair","Poor"];
let answers = ['Excellent', 'Excellent', 'Excellent', 'Very good', 'Excellent' , 42, '👍']
let totals = {}

// Populate totals with available options
options.forEach(option => {
  totals[option] = 0
})

// Next tally up the answers, but only if the answer are valid options (typo's or invalid options will be ignored)
answers.forEach(answer => {
  if (answer in totals) totals[answer]++
})

console.log(totals)
// outputs: {Excellent: 4, Very good: 1, Good: 0, Fair: 0, Poor: 0}

#4

I’d like to provide an alternate functional approach

You can reduce the options list to an object
using the initial values (lowercased) as keys
and the count of matches as values

let options = ["Excellent","Very good","Good","Fair","Poor"]; 
let answers = [ 'Excellent', 'Excellent', 'Excellent', 'Very good', 'Excellent' ];

let totals = options.reduce((r, i)=>({ ...r, [i.toLowerCase()]: answers.filter(a=> a==i).length }), {});

#5

I would definitely avoid doing that. It’s good that you’ve managed to get it on one line, but it’s not helpful for someone trying to learn. To be honest, it’s not even helpful for someone more experienced as it would break quite a few common pre-commit hook rules


#6

One line wasn’t an objective, i just didn’t think it needed to be broken up.
Lets see if I can improve it a bit …

let totals = options.reduce((result, item) => ({
  // keep the other counts
  ...result,

  // in a property called the name(lowercase), store the count of matches
  [item.toLowerCase()]: answers.filter(answer => answer==item).length
}), {});

It depends on what they’re trying to learn - if they want to use loops and mutations, sure.
I was wanting to provide an alternative using functions to transform the data with built-in array operations.
Partly because they’re neat, partly because I find it simpler to work in lists and transforms and want others to see that way of doing it in case they too prefer it :wink:

Afraid I’m not familiar with the pre-commit hook rules you mean :frowning:


#7

That’s awesome! I didn’t mean to come off as snarky or offputting if I did. Your example is succinct and you’ve even taken the extra step to account for lowercase in one line!

It’s generally a good idea to break up the code as you did on multiple lines - this helps you later on when you come back to the code or when you need to debug. I agree that it’s definitely much more neat now and I 100% agree with what your saying. But without commenting it’s hard for someone to learn from and generalize it (in other words, it’s hard for someone to see what exactly is being done so that they can prefer it too).

Basically, a pre-commit hook checks your code when you commit it and if any rules are broken (“complex” code, linting issues, functions that are too complex etc) then the commit is blocked.