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:
- Does the function provide an error for invalid input types?
- Does the function work as expected with no items in the array?
- Does the function work as expected with positive numbers?
- Does the function work as expected with negative numbers?
- 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([]));
}
}
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';
}
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
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
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
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';
}
Thanks for reading and see you in the next one!
Top comments (8)
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:Sidenote on
array_reduce
performance: for arrays of length > 1000 elements,array_sum
is faster thanarray_reduce
by an order of magnitude.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.
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!
Wow... That's a really good solution. I mean one line of actual code!
late to this but ...
odd_or_even = (arr) => arr.length == 0 ? 'even' : arr.reduce((acc, each) => acc + each) % 2 == 0 ? 'even' : 'odd'
This breaks some critical clean code principles, to name a few:
odd_or_even
has no block assignment (var
,const
,let
)==
instead of===
for value checksDon’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.
thanks
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 🤷♂️.