enteo
enteo

Reputation: 11

Powershell even and odd numbers

It get a file as a parameter and I need the sum of the even and odd numbers in the even and odd lines of the file

Input:
1 2 3 4 5
2 3 9 5
4 6 1
6 3 1 2 4
Output:
Sum of odd numbers:(1+3+5+1)=10
Sum of even numbers:(2+6+2+4)=12

I tried with foreach and without it, but I don't know how to convert strings from a file to an integer and put it an array

Upvotes: 0

Views: 5175

Answers (4)

Santiago Squarzon
Santiago Squarzon

Reputation: 60518

I guess I'll post my solution to this question too, didn't want to at the moment because I thought it was homework but since there are already 2 answers and since I did already had the code...

The code is very similar to Theo's answer.

using namespace System.Collections.Generic
using namespace System.Linq

$i = $false
$oddArray = [list[int]]::new()
$evenArray = [list[int]]::new()

foreach($line in $array) {
    $numbers = $line -split '\s+'
    if($i = -not $i) {
        # Odd Lines
        foreach($number in $numbers) {
            # If this number is Odd
            if($number % 2) {
                $oddArray.Add($number)
            }
        }
        continue
    }
    #Even Lines
    foreach($number in $numbers) {
        # If this number is even
        if(-not ($number % 2)) {
            $evenArray.Add($number)
        }
    }
}

[string]::Format(
    "Sum of odd numbers: ({0}) = {1}",
    ($oddArray -join ' + '),
    [Enumerable]::Sum($oddArray)
)
[string]::Format(
    "Sum of even numbers: ({0}) = {1}",
    ($evenArray -join ' + '),
    [Enumerable]::Sum($evenArray)
)

Upvotes: 1

Carby
Carby

Reputation: 1

Looking at others I felt the string generation could be simplified. Also use (abuse?) of Powershell dynamic casting. A bit of google research including random other pages provided inspiration and useful bits.

#read input, split on any whitespace
$inputFile = (Get-Content "C:\temp\numbers.txt") -split "\s"

#generate odds and evens arrays.
$inputFile | foreach{ if($_ % 2 -eq 0) {$evens += $_} else{$odds += $_}}

#make output strings
"Sum of odd numbers:(" + ($odds -join '+') + ")=" + (($odds|Measure-Object -Sum).Sum)
"Sum of even numbers:(" + ($evens -join '+') + ")=" + (($evens|Measure-Object -Sum).Sum)

Upvotes: 0

Steven
Steven

Reputation: 7087

I wrote this yesterday, but questioning if the question was homework, I initially didn't want to post. That said, since others are working on it, I figured I should go ahead and share.

$Numbers = @( Get-Content 'C:\temp\numbers.txt' )
$EvenOdd = @{ 0 = 'even'; 1 = 'odd' }

For( $i = 0; $i -lt $Numbers.Count; ++$i )
{    
    $LineOdd = $i % 2
    $Sum =
    $Numbers[$i].Trim() -Split "\s+" |
    Where-Object{ $_ % 2 -eq $LineOdd } |
    Measure-Object -Sum |
    Select-Object -ExpandProperty Sum

    "Line {0} : Sum of {1} numbers:({2})={3}" -f $i, ($EvenOdd[$LineOdd]), ($NumberArray -Join '+'), $Sum
}

Result:

Line 0 : Sum of even numbers:(2+4)=6
Line 1 : Sum of odd numbers:(3+9+5)=17
Line 2 : Sum of even numbers:(4+6)=10
Line 3 : Sum of odd numbers:(3+1)=4

To consider the 1st line Line# 1 a few minor adjustments:

$Numbers = @( Get-Content 'C:\temp\numbers.txt' )
$EvenOdd = @{ 0 = 'even'; 1 = 'odd' }

For( $i = 1; $i -le $Numbers.Count; ++$i )
{    
    $LineOdd = $i % 2
    $Sum =
    $Numbers[$i-1] -Split "\s+" |
    Where-Object{ $_ % 2 -eq $LineOdd } |
    Measure-Object -Sum |
    Select-Object -ExpandProperty Sum

    "Line {0} : Sum of {1} numbers:({2})={3}" -f $i, ($EvenOdd[$LineOdd]), ($NumberArray -Join '+'), $Sum
}

Note: I was originally splitting on a regular space. I took the split on whitespace idea and the .Trim() from Theo's example. I didn't bother casting to [int].

Note: These examples aren't comparable to Theo's answer. It's clear that we interpreted the question differently. If I have time I'll work the other interpretation.


Alternate sums all numbers from odd & even lines respectively:

$Numbers     = @( Get-Content 'C:\temp\numbers.txt' )
$EvenNumbers = [System.Collections.Generic.List[int]]::new()
$OddNumbers  = [System.Collections.Generic.List[int]]::new()

For( $i = 1; $i -le $Numbers.Count; ++$i )
{
    $LineOdd = $i % 2
    $NumberHash =
    $Numbers[$i-1].Trim() -Split "\s+" |
    Group-Object { $_ % 2 } -AsHashTable

    Switch ($LineOdd) 
    {
        0 { $NumberHash[0].foreach( { $EvenNumbers.Add($_) } ); Break }
        1 { $NumberHash[1].foreach( { $OddNumbers.Add($_) }  ); Break }
    }
}

$SumEven = ($EvenNumbers | Measure-Object -Sum).Sum
$SumOdd  = ($OddNumbers | Measure-Object -Sum ).Sum

"Sum of odd lines  : {0}{1}" -f "($($OddNumbers -join '+'))=",$SumOdd
"Sum of even lines : {0}{1}" -f "($($EvenNumbers -join '+'))=", $SumEven

In retrospect this would work just as well with a ForEach-Object{} in place of Group-Object & Switch, so I added another example:

$Numbers     = @( Get-Content 'C:\temp\numbers.txt' )
$EvenNumbers = [System.Collections.Generic.List[int]]::new()
$OddNumbers  = [System.Collections.Generic.List[int]]::new()

For( $i = 1; $i -le $Numbers.Count; ++$i )
{
    $LineOdd = $i % 2
    $Numbers[$i-1].Trim() -Split "\s+" |
    ForEach-Object{
        If( !$LineOdd -and $_ % 2 -eq 0 ) {
            $EvenNumbers.Add($_)
        }
        Elseif( $LineOdd -and $_ % 2 -eq 1 ) {
            $OddNumbers.Add($_)
        }
    }
}

$SumEven = ($EvenNumbers | Measure-Object -Sum).Sum
$SumOdd  = ($OddNumbers | Measure-Object -Sum ).Sum

"Sum of odd lines  : {0}{1}" -f "($($OddNumbers -join '+'))=",$SumOdd
"Sum of even lines : {0}{1}" -f "($($EvenNumbers -join '+'))=", $SumEven

And a more efficient & eloquent version of that last one:

$Numbers = @( Get-Content 'C:\temp\numbers.txt' )

$Sum = @{
    0 = [System.Collections.Generic.List[int]]::new()
    1 = [System.Collections.Generic.List[int]]::new()
}

For( $i = 1; $i -le $Numbers.Count; ++$i )
{
    $LineOdd = $i % 2    
    $Numbers[$i-1].Trim() -Split "\s+" |
    ForEach-Object{ 
        If( $_ % 2 -eq $LineOdd ) {
            $Sum[$LineOdd].Add($_) 
        }
    }
}

$SumOdd  = ($Sum[1] | Measure-Object -Sum).Sum
$SumEven = ($Sum[0] | Measure-Object -Sum).Sum

"Sum of odd lines  : {0}{1}" -f "($($Sum[0] -join '+'))=", $SumOdd
"Sum of even lines : {0}{1}" -f "($($Sum[1] -join '+'))=", $SumEven

So, this is an improvement because it only needs a single If statement inside the loop. It also prevents a significant number of modulus calculations. In the previous sample I had an If/ElseIf ergo every time the ElseIf fires a second modulus calculation would occur. granted, I could've pre-calculated a variable, but that wouldn't have completely removed the Else.... Instead by storing the collections in a hash a simple comparison is all that's needed to know which collection to append.

Note: The last 3 examples start at Line 1 and consider line 1 odd. As opposed to line 0...

Upvotes: 1

Theo
Theo

Reputation: 61158

This is one way of doing this.

The code below uses a Here-String dummy representation of the input file, but in real life you would use

$fileIn = Get-Content -Path 'Path\To\The\FileWithNumbers.txt'
$fileIn = @"
1 2 3 4 5
2 3 9 5
4 6 1
6 3 1 2 4
"@ -split '\r?\n'

$oddLine = $true            # first line is an odd line
$oddTotal, $evenTotal = 0   # create two variables to total the numbers
foreach ($line in $fileIn) {
    [int[]]$numbers = $line.Trim() -split '\s+'  # split on whitespace(s) and cast to [int]
    foreach ($n in $numbers) {
        if ($oddLine) {
            if ($n % 2) { $oddTotal += $n }
        }
        else {
            if (($n % 2) -eq 0) { $evenTotal += $n }
        }
    }
    $oddLine = !$oddLine # toggle odd and even line
}


"Sum of odd numbers in odd lines:   $oddTotal"
"Sum of even numbers in even lines: $evenTotal"

Result:

Sum of odd numbers in odd lines:   10
Sum of even numbers in even lines: 14

P.S. there's a mistake in your example output: 2+6+2+4 equals 14, not 12 ;)


If your output also needs to show the numbers added, you can do something like this:

$oddLine = $true            # first line is an odd line
# create two collection objects to gather all the numbers
$oddNumbers  = [System.Collections.Generic.List[int]]::new()  
$evenNumbers = [System.Collections.Generic.List[int]]::new()
foreach ($line in $fileIn) {
    [int[]]$numbers = $line.Trim() -split '\s+'  # split on whitespace(s) and cast to [int]
    foreach ($n in $numbers) {
        if ($oddLine) {
            if ($n % 2) { $oddNumbers.Add($n) }
        }
        else {
            if (($n % 2) -eq 0) { $evenNumbers.Add($n) }
        }
    }
    $oddLine = !$oddLine # toggle odd and even line
}

# calculate the totals from the lists
$oddTotal  = ($oddNumbers | Measure-Object -Sum).Sum
$evenTotal = ($evenNumbers | Measure-Object -Sum).Sum

"Sum of odd numbers in odd lines:   $oddTotal ($($oddNumbers -join '+'))"
"Sum of even numbers in even lines: $evenTotal ($($evenNumbers -join '+'))"

Result:

Sum of odd numbers in odd lines:   10 (1+3+5+1)
Sum of even numbers in even lines: 14 (2+6+2+4)

Upvotes: 1

Related Questions