DEV Community

James Robb
James Robb

Posted on • Updated on

Odd or Even?

Task description

Given an array of numbers, determine whether the sum of all of the numbers is odd or even.

Give your answer in string format as 'odd' or 'even'.

If the input array is empty consider it as an array with a zero.

Example:
odd_or_even([]) returns "even"
odd_or_even([0]) returns "even"
odd_or_even([2, 5, 34, 6]) returns "odd"
odd_or_even([0, -1, -5]) returns "even"
Have fun!

Task solution

Tests

We want to test a couple of things:

  1. Does the function provide an error for invalid input types?
  2. Does the function work as expected with no items in the array?
  3. Does the function work as expected with positive numbers?
  4. Does the function work as expected with negative numbers?
  5. Does the function return the correct value with mixed numbers?

For the tests, I have used PHPUnit.

class OddOrEvenTests extends TestCase {
  public function testInvalidInputThrowsTypeError() {
    $this->expectException(TypeError::class);
    odd_or_even(1);
  }

  public function testNegativeNumbers() {
    $this->assertEquals('even', odd_or_even([0, -1, -5]));
  }

  public function testPositiveNumbers() {
    $this->assertEquals('odd', odd_or_even([2, 5, 34, 6]));
  }

  public function testMixed() {
    $this->assertEquals('odd', odd_or_even([0, -1, -5, 2, 5, 34, 6, 2.3]));
  }

  public function testSingleNumber() {
    $this->assertEquals('even', odd_or_even([0]));
  }

   public function testEmpty() {
    $this->assertEquals('even', odd_or_even([]));
  }
}
Enter fullscreen mode Exit fullscreen mode

Implementation

function addition_reducer(int $accumulator, int $item): int {
  return $accumulator + $item;
}

function odd_or_even(array $integer_array): string {
  $reduced = array_reduce($integer_array, addition_reducer, 0);
  return $reduced % 2 === 0 ? 'even' : 'odd';
}
Enter fullscreen mode Exit fullscreen mode

The addition_reducer does exactly as it states when used via array_reduce. It will take the $accumulator, in our case 0, then on each iteration of the $integer_array, it will add the $item to the $accumulator. Once this is done, the next item in the array will be added to the previous iterations return value, which will now be the $accumulator.

After transforming our array we check if the reduced value divided by 2 has no leftover value using the % operator. All this means is that if we want to be sure a number is divisible by any other, we could just do number % divider === 0 and if that is true, we know it is divisible as a whole number.

All that being the case, we can run our check on our $reduced number returned and run the % operator on it with 2 as our divider, if the operation returns 0, we know it is an even number since it is wholly divisible by 2 with no leftovers, otherwise, it must be odd.

Sidenote 1: The % operator

The naming of the operator can be a bit confused I have dound, with some referring to it as modulus and others as modulo. This is understandable though since there is both a modulus and a modulo and both are interconnected. The definition of each is slightly different however and are outlined as follows:

The Modulus is the remainder of the euclidean division of one number by another. % is called the modulo operation.

For instance, 5 divided by 3 equals 1.6666666666666667 but the remainder is 2. This being the case we can say:

  • 5 / 3 = 1.6666666666666667
  • 5 % 3 = 2

The modulo operator itself can be represented as a - floor(a / b) * b. This being the case we could write a helper function to get the same result as the % operator, in javascript for example we would write such a helper like so:

function modulo(a, b) {
 return a - Math.floor(a / b) * b;
}

modulo(5, 3) // 2
Enter fullscreen mode Exit fullscreen mode

Sidenote 2: Reducers

Reducers take something and transform it into something else, usually they will be used on arrays, objects, collections or some other form of iterable. In our case we want to transform an array of numbers into just a number which is to be the summed value of each number in the array.

A reducer in such cases is just a fancy kind of loop, other such special loops include map, filter, reduce and much more, usually fully built in to the language. In PHP they are simply array_map, array_filter and array_reduce respectively. In JavaScript the are [].map, [].filter and [].reduce. More such special loop types exist but these are the main 3 you'll use.

If we were to reproduce the array_reduce line from above with a similar foreach based approach, we could do something like this:

$items = [1, 2, -3];
$final_value = 0;
foreach($items as $item) {
 $final_value += $item;
}
echo $final_value; // 0
Enter fullscreen mode Exit fullscreen mode

Our reducer is basically doing the same as the above code but in a more functional and descriptive manner with less lines of code required.

$array = [1, 2, -3];
$initial_value = 0;
$reduced = array_reduce($array, addition_reducer, $initial_value);
echo $reduced; // 0
Enter fullscreen mode Exit fullscreen mode

Conclusions

Overall this task was quite easy but things like the modulo operator (%) are always fun to work with since they do something in a way you wouldn't normally approach things and yet are hyper useful in day to day programming as you will see in an upcoming post on The Mars Rover Kata as the % operator will literally and figuratively be a driving force for the solution to that challenge.

I don't think I would change anything in the implementation, I mean I could use the array_sum function in PHP to avoid the array_reduce and addition_reducer functions but I prefer to use a reducer because people coming from other languages would be more likely to recognise a reducer comparitively to a language specific function like array_sum. If I were to do that version though, the whole solution would look like this:

function odd_or_even(array $integer_array): string {
  $reduced = array_sum($integer_array);
  return $reduced % 2 === 0 ? 'even' : 'odd';
}
Enter fullscreen mode Exit fullscreen mode

Thanks for reading and see you in the next one!

Discussion (11)

Collapse
citizen428 profile image
Michael Kohl

I prefer to use a reducer because people coming from other languages would be more likely to recognise a reducer comparitively to a language specific function like array_sum

I'd say array_sum is a name that's very intent revealing, and plenty of other languages have sum methods too, e.g. here's how you could solve this Kata in Ruby:

def odd_or_even(arr)
  arr.sum.even? ? 'even' : 'odd'
end
Collapse
jamesrweb profile image
James Robb Author

I haven't seen such a function in the languages I work with usually, outside of PHP that is, but interesting to see it exists elsewhere in the wild. For me I think a reducer is still more recognisable but good to know never the less, thanks for sharing!

Collapse
citizen428 profile image
Michael Kohl

It seems to exist in most places I encounter, Ruby, Python, Java 8+, C# etc. all have some form of sum as a special case of reduce. I guess the one notable exception is once again JS 🙄

Thread Thread
jamesrweb profile image
James Robb Author

I guess I wasn't aware of those implementations then since Python and C# are languages I work with week to week but oh well, it happens 🤷‍♂️.

Collapse
lautarolobo profile image
Lautaro Lobo

Wow... That's a really good solution. I mean one line of actual code!

Collapse
citizen428 profile image
Michael Kohl

Ruby is a very expressive language, one of the reasons I’m still using it after 15 years.

Collapse
krlv profile image
eugene kirillov

I would say modulus operator is too powerful for this task. All you need to do to determine whether the number is odd or even, is to check number's first bit: 0 for even number, 1 for odd:

function odd_or_even(array $integer_array): string {
    return array_sum($integer_array) & 1 ? 'odd' : 'even';
}

Sidenote on array_reduce performance: for arrays of length > 1000 elements, array_sum is faster than array_reduce by an order of magnitude.

Collapse
jamesrweb profile image
James Robb Author

Bitwise checks are smart but most people don’t understand them and explaining them would’ve made for a longer article so using modulus was easier to show and explain for a larger audience plus it works perfectly well for this use case.

On the performance point I agree but I don’t care much for it since there isn’t any performance issues arisen worth an implementation change “premature optimisation is the root of all evil” and all that.

Collapse
fitsum profile image
fitsum

late to this but ...

odd_or_even = (arr) => arr.length == 0 ? 'even' : arr.reduce((acc, each) => acc + each) % 2 == 0 ? 'even' : 'odd'

Collapse
jamesrweb profile image
James Robb Author

This breaks some critical clean code principles, to name a few:

  1. odd_or_even has no block assignment (var, const, let)
  2. The one liner is unnecessary and makes the code harder to read and understand
  3. Duplication of ‘even’ which should be a variable if reused but cannot be in a one line context and doesn’t need to be in a block context as in my version
  4. Using == instead of === for value checks

Don’t get me wrong, this will function fine enough but functioning doesn’t mean its good.

We developers read code far more than we write it and further to that, the industry has more juniors than seniors at any time which makes the readability aspect all the more important. Lastly, proper equality checks and block assignments are essential in languages like JavaScript because global scope pollution can result in overrides and improper equality checks can result in false positives.

Collapse
fitsum profile image
fitsum

thanks