Skip to content
Menu
The Lonely Administrator
  • PowerShell Tips & Tricks
  • Books & Training
  • Essential PowerShell Learning Resources
  • Privacy Policy
  • About Me
The Lonely Administrator

Solving Another PowerShell Math Challenge

Posted on March 22, 2021March 22, 2021

Last month, the Iron Scripter Chairman posted a "fun" PowerShell scripting challenge. Actually, a few math-related challenges . As with all these challenges, the techniques and concepts you use to solve the challenge are more important than the result itself. Here's how I approached the problems.

Manage and Report Active Directory, Exchange and Microsoft 365 with
ManageEngine ADManager Plus - Download Free Trial

Exclusive offer on ADManager Plus for US and UK regions. Claim now!

Problem #1

The first challenge was to take a number, like 2568, and get the sum total of the individual integers.

2+5+6+8

The answer being 21. You can probably think of a few ways to split the string into individual elements. I decided to use regular expressions.

[int]$i = 12931

#define a regex pattern to match a single digit
[regex]$rx="\d{1}"

Each regular expression match object value will be the individual number. I can easily pipe the values to Measure-Object to get the sum.

#get all matches and add them up
$measure = $rx.Matches($i) | Measure-Object -Property Value -Sum

#write the sum to the pipeline
$measure.sum

This is easy enough to turn into a function.

Function Get-NumberSum {

    [cmdletbinding()]
    [OutputType([Int])]
    Param(
        [Parameter(Position = 0, Mandatory, HelpMessage = "Enter an integer value like 1234")]
        [Alias("i")]
        [int]$Value
    )

    #define a regex pattern to match a single digit
    [regex]$rx = "\d{1}"

    #get all matches and add them up
    $measure = $rx.Matches($Value) | Measure-Object -Property Value -Sum

    #write the sum to the pipeline
    $measure.sum
}

The function wants an integer. But the regular expression pattern works on anything with numbers in it.

($rx.matches("A12B9C31D") | measure value -sum).sum

This gives me the same answer of 16. The challenge had some bonus elements, so here is a slightly more advanced version of the function.

Function Get-NumberSum {
    [cmdletbinding()]
    [OutputType([Int])]
    [OutputType("NumberSum")]
    [Alias("gns")]
    Param(
         [ValidateScript({
            if ($_.ToString().Length -le 10) {
                $True
            }
            else {
                Throw "Specify a value of 10 digits or less."
                $False
            }
        })]
        [int64]$Value,
        [switch]$Quiet
    )

    Write-Verbose "Processing $Value"
    #define a regex pattern to match a single digit
    [regex]$rx = "\d{1}"

    $values = $rx.Matches($Value).Value
    Write-Verbose ($values -join "+")

    $measure =  $Values | Measure-Object -Sum
    Write-Verbose "Equals $($measure.sum)"

    if ($Quiet) {
        $measure.sum
    }
    else {
        [pscustomobject]@{
            PSTypeName = "NumberSum"
            Value = $Value
            Elements = $values
            Sum = $measure.sum
        }
    }
}

This version will create a custom object by default. The -Quiet parameter shows only the result. The parameter validation could be handled in a number of ways. If I kept the type for $Value as [int], the number can't be more than 10 digits anyway. But I wanted to try something different. So I'm using a ValidateScript attribute to display a custom error message. Here's what it looks like using the function alias.

Ok, I'll admit using a regular expression is a little overkill for this challenge, but it is fun. Here's an even simpler way.

($i -split "" | measure-object -sum).sum

Problem #2

The second problem was a bit more challenging. Given an array of numbers, what are all the possible unique sums.

$a = 2,5,6

2
5
6
2+5 = 7
2+5+6 = 13
2+6 = 8
5+6 = 11

This problem requires getting the sum of numbers from the array, and taking all possible combinations into account. The trick is to recursively call the function, reducing the numbers to test in combination.

function Get-ReductiveSum {
    param([array]$Numbers,[int]$Index=0,[int]$Sum=0)

    if ($numbers.count -eq $index) {
        $sum
    }
    else {
        Get-ReductiveSum $numbers -index ($index+1) -sum ($sum+$numbers[$index])
        Get-ReductiveSum $numbers ($index+1) $sum
    }
}

I can use the function like this.

To meet the challenge objectives and make this easy to use, I created this "parent" function.

Function Get-PossibleSum {
    [cmdletbinding()]
    Param(
        [Parameter(Position = 0, Mandatory)]
        [ValidateRange(1,9)]
        [int[]]$Values
    )

    #nested function
    function Get-ReductiveSum {
        param([array]$Numbers,[int]$Index=0,[int]$Sum=0)

        Write-Verbose "Get-ReductiveSum -Numbers $($numbers -join ',') -index $index -sum $sum"
        if ($numbers.count -eq $index) {
            Write-Verbose "Found sum $sum"
            $sum
        }
        else {
            Write-Verbose "Reducing numbers to $($numbers -join ',')"
            Write-Verbose "Setting index to $($index+1)"
            Write-Verbose "Get-ReductiveSum $($sum+$numbers[$index])"
            Get-ReductiveSum $numbers -index ($index+1) -sum ($sum+$numbers[$index])
            Write-Verbose "Get-ReductiveSum $sum"
            Get-ReductiveSum $numbers ($index+1) $sum
        }
    }

    Write-Verbose "Using values $($values -join ',')"
    Write-Verbose "Verifying unique values"
    $values = $values | Get-Unique
    if ($values.count -gt 9) {
        #this should probably never happen
        Write-Warning "You specified $($values.count) values. Only using the first 9"
        $Values = $Values[0..8]
    }
    Write-Verbose "Calculating possible unique sums for $($values -join ',')"
    $result  =  Get-ReductiveSum $Values | Where-Object {$_ -gt 0}
    Write-Verbose "Found $($result.count) non-zero sums"
    $result | Sort-Object
}

I'll let you try the code to see the Verbose output.

Getting your brain to think the PowerShell way can be tough. That's why these challenges are so helpful. The more you can follow the PowerShell pipeline in your head, the easier it will be for you to use.


Behind the PowerShell Pipeline

Share this:

  • Click to share on X (Opens in new window) X
  • Click to share on Facebook (Opens in new window) Facebook
  • Click to share on Mastodon (Opens in new window) Mastodon
  • Click to share on LinkedIn (Opens in new window) LinkedIn
  • Click to share on Pocket (Opens in new window) Pocket
  • Click to share on Reddit (Opens in new window) Reddit
  • Click to print (Opens in new window) Print
  • Click to email a link to a friend (Opens in new window) Email

Like this:

Like Loading...

Related

4 thoughts on “Solving Another PowerShell Math Challenge”

  1. Pingback: ICYMI: PowerShell Week of 26-March-2021 – PowerShell.org
  2. Pingback: PowerShell SnippetRace 12-2021 | PowerShell Usergroup Austria
  3. Alexander says:
    April 2, 2021 at 10:41 am

    It blew my mind. I don’t understand how the Get-ReductiveSum function works.

    1. Jeffery Hicks says:
      April 2, 2021 at 10:53 am

      To be honest, I found a C# example that I turned into PowerShell. Take a look at https://stackoverflow.com/questions/403865/algorithm-to-sum-up-a-list-of-numbers-for-all-combinations.

Comments are closed.

reports

Powered by Buttondown.

Join me on Mastodon

The PowerShell Practice Primer
Learn PowerShell in a Month of Lunches Fourth edition


Get More PowerShell Books

Other Online Content

github



PluralSightAuthor

Active Directory ADSI Automation Backup Books CIM CLI conferences console Friday Fun FridayFun Function functions Get-WMIObject GitHub hashtable HTML Hyper-V Iron Scripter ISE Measure-Object module modules MrRoboto new-object objects Out-Gridview Pipeline PowerShell PowerShell ISE Profile prompt Registry Regular Expressions remoting SAPIEN ScriptBlock Scripting Techmentor Training VBScript WMI WPF Write-Host xml

©2025 The Lonely Administrator | Powered by SuperbThemes!
%d