3

Important edit : I can't use filter - the purpose is pedagogic.

I have an array in which I would want to count the number of its elements that verify a boolean, using only map and reduce.

Count of the array's size

I already wrote something that counts the array's size (ie. : the number of all of its elements), using reduce :

const array_numbers = [12, 15, 1, 1]; // Size : 4
console.log(
              array_numbers.reduce((acc) => {
                return acc + 1;
              }, 0)
);

Count of the array's elements checking a boolean condition

Now I would want to count only the elements that verify a boolean condition. Thus, I must use map before reduce and the elements of the map's returned array will be only the good elements.

So I wrote this code but it doesn't work... Indeed, I put null when I encounter a not-good element (and null is counted as en element unfortunately).

NB : here, the boolean condition is "is the element even ? (%2 == 0)".

const array_numbers = [12, 15, 1, 1]; // Size : 4
console.log(
              array_numbers.map((current_value) => {
                if(current_value % 2 == 0) {
                  return current_value;
                }
                return null;

              }).reduce((acc) => {
                return acc + 1;

              }, 0)
);
JarsOfJam-Scheduler
  • 2,809
  • 3
  • 31
  • 70

4 Answers4

5

Array#filter the array and check the length:

const array_numbers = [12, 15, 1, 1];
const result = array_numbers.filter((n) => n % 2 === 0).length;

console.log(result);

Or count using Array#reduce:

const array_numbers = [12, 15, 1, 1, 4];
const result = array_numbers.reduce((r, n) => n % 2 ? r : r + 1, 0);

console.log(result);

Or if you must, you can use Array#map with Array#reduce:

const array_numbers = [12, 15, 1, 1, 4];
const result = array_numbers
  .map((n) => n % 2 === 0 ? 1 : 0) // map to 1 or 0 according to the condition
  .reduce((r, n) => r + n); // sum everything

console.log(result);
Ori Drori
  • 183,571
  • 29
  • 224
  • 209
  • Thank you, but I can't use `filter` (pedagogic exercise). I modified the OP to indicate this. Sorry =/ – JarsOfJam-Scheduler Jan 03 '17 at 16:52
  • I've added an answer with reduce. – Ori Drori Jan 03 '17 at 16:53
  • Aaah I didn't think to use `reduce` like that, thank you ! – JarsOfJam-Scheduler Jan 03 '17 at 16:55
  • I've added another one with map and reduce for the sake of it. – Ori Drori Jan 03 '17 at 16:56
  • Thank you again. :) Do you know if it's possible to use only `map` if I want to verify that all elements verify the boolean condition ? (so it's a bit different) – JarsOfJam-Scheduler Jan 03 '17 at 17:12
  • You can map all elements to `true` or `false`, and then check that everything `true` using `every` or `reduce`. – Ori Drori Jan 03 '17 at 17:13
  • Ah tank you, and tell me if i am wrong but using only `reduce` is not possible (because it returns either `true` or `false` and the accumulator value, if set at `false`, should not change to `true` - the below code is thus wrong : `array_numbers.reduce((acc, current_value) => { if(current_value % 2 != 0) { return false; } else { return true;} }, true)` – JarsOfJam-Scheduler Jan 03 '17 at 17:20
  • Indeed. I wrote this : `array_numbers.reduce((acc, current_value) => { return acc || (current_value % 2 == 0) }, false)` to verify if at least one element is even (inspired by you) ; it seems to work fine, could you confirm please ? :) – JarsOfJam-Scheduler Jan 03 '17 at 17:56
  • It works. My previous comment has a mistake. I should've initialized it with a `true`. – Ori Drori Jan 03 '17 at 17:58
  • Array#reduce is even simpler. The accumulator can be a Boolean as well - array_numbers.reduce((acc, current_value) => acc && (current_value % 2) === 0, true); – Ori Drori Jan 03 '17 at 17:59
  • Ahah yes thank you ^^ Do you know when is `map` useful for these kinds of "programs" (so to work with collection) ? because in fact, `reduce` is really powerful and seems to be able to replace `map` anywhere.. =/ – JarsOfJam-Scheduler Jan 03 '17 at 18:19
  • `reduce` is a swiss knife, while `map` and `filter` are targeted for specific situation. This is a good time to do some reading. Good luck :) – Ori Drori Jan 03 '17 at 18:29
2

You can use Array.prototype.filter to filter the even numbers - and you don't need the reduce() function - you can use length of the array returned by the filter() function.

Or you can use reduce() method alone like below:

See demos below:

const array_numbers = [12, 15, 1, 1]; // Size : 4

// using filter
console.log(
  array_numbers.filter((current_value) => {
    return current_value % 2 == 0;
  }).length
);

// using reduce
console.log(
  array_numbers.reduce((prev, curr) => {
    return curr % 2 == 0 ? prev + 1 : prev;
  }, 0)
);
kukkuz
  • 41,512
  • 6
  • 59
  • 95
1

Since per your comment you must use reduce for some reason:

arr.reduce((acc, n) => { n % 2 ? acc + n : acc }, 0);

The map is unecessary.

Jared Smith
  • 19,721
  • 5
  • 45
  • 83
1

As Jared Smith mentioned, you don't need to use map for this task. Array.reduce() gets the current element as a second argument in the callback function which you can use to check if it satisfies your given condition.

So, again assuming that you must use either map and/or reduce:

const myArray = [1,2,3,4,5,6];
const condition = function(a) {
  // let's say
  return a %2 == 0;
}

let result = myArray.reduce((acc, val) => {
  return condition(val) ? acc + 1 : acc
  }, 0);

console.log(result);
vassiliskrikonis
  • 566
  • 2
  • 10