Daily Challenge #81 - Even or Odd

dev.to staff on October 02, 2019

Given a string of numbers confirm whether the total of all the individual even numbers are greater than the total of all the individual odd numbers... [Read Full]
markdown guide
 

Haskell

Since I'm not entirely sure what a string of numbers means, I just assumed the function gets a list of integers.

import Data.List (partition)

fight :: [Int] -> String
fight = answer . add . partition even
  where
    add (evens, odds) = (sum evens, sum odds)
    answer (evens, odds)
      | evens == odds = "Even and Odd are the same"
      | evens > odds  = "Even is greater than Odd"
      | otherwise     = "Odd is greater than Even"
 

Could you explain what add (evens, odd) is (data type) and what does this piece do please?

 

Sure! Let's start at partition, since we pass its output to add. Partition takes a predicate function and returns a tuple ([Int], [Int]) with the items of the list for which the predicate is true in the first position and the items for which the predicate is false in the second position. In this case, in the first position we'll have all the even numbers and in the second all the odd numbers, since we're using even as predicate.

Then add receives this tuple, which I destructure for convenience, and applies the function sum to both elements, which sums all the items in each list.

And the function signature for add would look like this.

add :: ([Int], [Int]) -> (Int, Int)

Lastly, answer takes the output of add and checks the conditions in the guards (the | <condition> thing) and returns the string for the first condition that matches or the string after otherwise if none matches.

Awesome, thanks for your answer! I didn't know the add function could take a tuple. Good to know!

 

Elixir:

defmodule Day81 do
  require Integer

  @spec even_or_odd(String.t()) :: String.t()
  def even_or_odd(string) do
    {even, odd} =
      string
      |> String.graphemes()
      |> Enum.map(&String.to_integer/1)
      |> Enum.split_with(&Integer.is_even/1)

    {even, odd} = {Enum.sum(even), Enum.sum(odd)}

    cond do
      even > odd -> "Even is greater than Odd"
      odd > even -> "Odd is greater than Even"
      true -> "Even and Odd are the same"
    end
  end
end
 

I read graphmemes instead of graphemes, I should probably stop browsing the internet for today...

 
 

Rust

Rather than keeping two sums, we can negate one of the options (I chose to negate the evens) and compare the sum to 0:

use std::cmp::Ordering;

fn compare_even_to_odd(numbers: impl Iterator<Item = i64>) -> String {
    let comparison = numbers.map(|number| if number % 2 == 0 {
            - number
        } else {
            number
        }
    ).sum::<i64>().cmp(&0);
    match comparison {
        Ordering::Less => "Even is greater than Odd".to_owned(),
        Ordering::Equal => "Even and Odd are the same".to_owned(),
        Ordering::Greater => "Odd is greater than Even".to_owned(),
    }
}
fn main() {
    println!("{}", compare_even_to_odd((&[1, 3, 4]).iter().map(|a| (*a))));
}
 

Some JavaScript

const evenVsOdd = str => {
   const evens = str.split('').filter(x => x % 2 == 0).reduce((a, b) => a + parseInt(b), 0)
   const odds = str.split('').filter(x => x % 2 != 0).reduce((a, b) => a + parseInt(b), 0)

   return evens > odds ? "Even is greater than Odd"
      : evens == odds ? "Even and Odd are the same"
      : "Odd is greater than Even"
}
 

Elm

module EvenOdd exposing (evenOdd)


compareEvensOdds : ( Int, Int ) -> String
compareEvensOdds ( evens, odds ) =
    case compare evens odds of
        GT ->
            "Even is greater than Odd"

        LT ->
            "Odd is greater than Even"

        _ ->
            "Even and Odd are the same"


evenOdd : String -> String
evenOdd =
    String.split ""
        >> List.map (String.toInt >> Maybe.withDefault 0)
        >> List.partition (modBy 2 >> (==) 0)
        >> Tuple.mapBoth List.sum List.sum
        >> compareEvensOdds

Tests

module EvenOddTest exposing (suite)

import EvenOdd exposing (evenOdd)
import Expect exposing (equal)
import Test exposing (Test, describe, test)


suite : Test
suite =
    describe "Even or odd"
        [ test "Evens should be greater than odds with 12" <|
            \_ ->
                evenOdd "12" |> equal "Even is greater than Odd"
        , test "Odds should be greater than evens with 123" <|
            \_ ->
                evenOdd "123" |> equal "Odd is greater than Even"
        , test "Evens & odds should be equal with 112" <|
            \_ ->
                evenOdd "112" |> equal "Even and Odd are the same"
        ]
 

Golang

I assumed string of numbers was an array.

package main

import "fmt"

func evenOrOdd(numbers [10]int) {
    evenSum := 0
    oddSum := 0

    for i := 0; i < len(numbers); i++ {
        check := numbers[i] % 2

        if check == 0 {
            evenSum += evenSum + numbers[i]
        } else {
            oddSum += oddSum + numbers[i]
        }
    }

    if evenSum > oddSum {
        fmt.Println("Even is greater than Odd")
    } else if evenSum < oddSum {
        fmt.Println("Odd is greater than Even")
    } else if evenSum == oddSum {
        fmt.Println("Even and Odd are the same")
    }
}

func main() {
    numbers := [10]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
    evenOrOdd(numbers)
}
 

F#

module DailyChallenge

open System.Text.RegularExpressions

let tuple2Map f (x, y) = (f x, f y)

let (|Greater|Smaller|Equal|) (x, y) =
    if x > y then Greater
    elif x < y then Smaller
    else Equal

let evenOrOdd (nums : string) : string =
    nums.Split(' ')
    |> Array.partition (fun n -> Regex.Match(n, "[02468]$").Success)
    |> tuple2Map (Array.sumBy (int))
    |> function
    | Greater -> "Even is greater than Odd"
    | Smaller -> "Odd is greater than Even"
    | Equal -> "Even and Odd are the same"

Tried to have a bit of fun with this one:

  • Input strings are assumed to be of the form "1 2 3" etc.
  • To save a map call for converting the strings to numbers, I used regular expressions for the partitioning.
  • Implemented a little helper called tuple2Map for applying a function to both elements of a 2-tuple.
  • Used an active pattern for deciding which of the sums is greater.

Tests:

module DailyChallengeTest

open FsUnit.Xunit
open Xunit
open DailyChallenge

[<Fact>]
let ``evens > odds``() =
    evenOrOdd "1 2" |> should equal "Even is greater than Odd"

[<Fact>]
let ``evens < odds``() =
    evenOrOdd "1 2 3" |> should equal "Odd is greater than Even"

[<Fact>]
let ``evens = odds``() =
    evenOrOdd "1 3 4" |> should equal "Even and Odd are the same"
 

D version, assuming that the string of numbers is a string with integers separated by spaces:

import std.stdio : writeln;
import std.array : split;
import std.conv : to;
import std.algorithm.iteration : map, sum;

string compareEvenOdd(string numbers) {
    auto result = numbers
        .split()
        .map!(a => to!int(a))
        .map!(a => a % 2 == 0 ? a : -a)
        .sum();
    return result < 0 ? "Odd is greater than Even" :
          (result > 0 ? "Even is greater than Odd" :
                        "Even and Odd are the same");
}    

void main() {
    compareEvenOdd("1 2 3 4 5 6 7 8 9").writeln();
    compareEvenOdd("1 3 6 98 35").writeln();
    compareEvenOdd("1 1 2 1 1 2 1 1 2").writeln();
}

Output:

Odd is greater than Even
Even is greater than Odd
Even and Odd are the same
 

A Swift solution:

unc solution(_ numbers: [Int]) -> String {
    var odds = 0
    var evens = 0

    for number in numbers {
        if (number % 2 == 0) {
            evens += number
        } else {
            odds += number
        }
    }

    if (evens > odds) {
        return "Even is greater than Odd"
    } else if (evens < odds) {
        return "Odd is greater than Even"
    }

    return "Even and Odd are the same"
}
 

c#, using linq, input validations omitted:

string evenOrOdd(string digitsOnly) 
{
    var evens = digitsOnly.Count(c => Char.GetNumericValue(c) % 2 == 0);
    var odds = digitsOnly.Length - evens;
    return evens > odds ? 
        "Even is greater than Odd" : 
        evens < odds ? 
            "Odd is greater than Even" : 
            "Even and Odd are the same";
}
 

My solution in js


const evenOrOdd = (str) => {
  const evenCount = (`${str}`.match(/[02468]/g) || '').length,
    oddCount = (`${str}`.match(/[13579]/g) || '').length;
  return (evenCount === oddCount) ? 'Even and Odd are the same' : (evenCount > oddCount ) ? 'Even is greater than Odd' : 'Odd is greater than Even';
};

 

A Swift solution:

import Foundation


/*
 evenOrOdds takes a list of numbers and outputs which total is greater, all odds, or all evens.

 @param numList: [Int] list of integers of any length

 @return String describing which value is greater or even they are equal.
 */
func evenOrOdds(_ numList:[Int]) -> String {
    let evenWin = "Even is greater than Odd"
    let oddWin  = "Odd is greater than Even"
    let draw    = "Even and Odd are the same"

    var accum = 0

    for num in numList {
        if num % 2 == 0 {
            accum += num
        } else {
            accum -= num
        }
    }

    if accum > 0 {
        return evenWin
    } else if accum < 0 {
        return oddWin
    }

    return draw
}




// utility function to generate a list of Ints
func genRandoms() {
    var randomGen = SystemRandomNumberGenerator.init()
    var randomList = [Int](repeating: 1, count: 100)

    for index in 0..<randomList.count {
        randomList[index] = Int(bitPattern: randomGen.next(upperBound: UInt(bitPattern: 500)))
    }

    print(randomList)
}


let example1 = [104, 258, 303, 66, 310, 363, 41, 180, 299, 208, 355, 135, 234, 214, 243, 350, 494, 408, 37, 438, 335, 101, 489, 449, 44, 136, 285, 408, 432, 350, 343, 271, 9, 286, 304, 451, 26, 388, 303, 259, 212, 434, 241, 20, 199, 201, 55, 318, 110, 48, 135, 359, 345, 277, 424, 23, 249, 348, 419, 301, 409, 316, 163, 81, 319, 440, 466, 185, 57, 102, 230, 446, 454, 369, 21, 284, 7, 161, 136, 113, 471, 2, 217, 350, 361, 334, 437, 421, 29, 290, 123, 326, 360, 142, 330, 354, 325, 140, 312, 116]

let example2 = [407, 461, 144, 458, 246, 103, 5, 241, 166, 75, 300, 215, 430, 424, 325, 283, 81, 420, 405, 485, 266, 23, 71, 42, 290, 189, 364, 382, 368, 203, 89, 317, 26, 465, 94, 84, 133, 223, 204, 189, 430, 400, 273, 476, 222, 246, 455, 137, 258, 470, 428, 242, 173, 285, 428, 147, 105, 306, 211, 489, 383, 414, 93, 433, 257, 449, 485, 183, 160, 302, 307, 227, 5, 361, 188, 18, 356, 442, 16, 409, 309, 152, 94, 319, 264, 147, 247, 359, 25, 364, 58, 144, 218, 16, 401, 62, 391, 110, 399, 24]

let example3 = [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2]

// used to generate a draw data set, but just explicitly defined after copying the output
//var example3 = [Int](repeating: 1, count: 50)
//example3.append(contentsOf: [Int](repeating: 2, count: 25))


print(evenOrOdds(example1),"")

print(evenOrOdds(example2),"")

print(evenOrOdds(example3),"\n")

Outputs:

Even is greater than Odd 
Odd is greater than Even 
Even and Odd are the same 

Program ended with exit code: 0

Went with accumulating by adding evens and subtracting odds so in a case where the list of values being summed up ends up greater than Int.max you don't get a runtime error...... not that these test cases are likely to total greater than 9223372036854775807.... haha

 

I just checked on Codewars the challenge, and the template for the JavaScript language is the following:

function evenOrOdd(str) {

}

and the tests are

// node 8.x.x

Test.assertEquals(evenOrOdd('12'), 'Even is greater than Odd');
Test.assertEquals(evenOrOdd('123'), 'Odd is greater than Even');
Test.assertEquals(evenOrOdd('112'), 'Even and Odd are the same');

If it can help you understand a little bit more the challenge (yes, the instructions in this article were confusing).

 
nums = str(input())
numi = [int(n) for n in nums]
odd = [n for n in numi if n%2 == 1]
if sum(odd) > int(sum(numi)/2):
   print("Odd is greater than Even")
elif sum(odd) < int(sum(numi)/2):
   print("Even is greater than Odd")
else:
   print("Even and Odd are the same")

code of conduct - report abuse