Gordon
Gordon

Reputation: 6883

Validate members of array

I have a string I am pulling from XML that SHOULD contain comma separated integer values. Currently I am using this to convert the string to an array and test each member of the array to see if it is an Int. Ultimately I still want an array in the end, as I also have an array of default success codes and I want to combine them. That said, I have never found this pattern of setting the test condition true then looping and potentially setting it to false to be all that elegant. So, I am wondering if there is a better approach. I mean, this works, and it's fast, and the code is easy to read, so in a sense there is no reason to change it, but if there is a better way...

$supplamentalSuccessCode = ($string.Split(',')).Trim()
$validSupplamentalSuccessCode = $true
foreach ($code in $supplamentalSuccessCode) {
   if ($code -as [int] -isNot [int]) {
      $validSupplamentalSuccessCode = $false
   }
}

EDIT: To clarify, this example is fairly specific, but I am curious about a more generic solution. So imagine the array could contain values that need to be checked against a lookup table, or local drive paths that need to be checked with Test-Path. So more generically, I wonder if there is a better solution than the Set variable true, foreach, if test fails set variable false logic. Also, I have played with a While loop, but in most situations I want to find ALL bad values, not exit validation on the first bad one, so I can provide the user with a complete error in a log. Thus the ForEach loop approach I have been using.

Upvotes: 1

Views: 1053

Answers (1)

mklement0
mklement0

Reputation: 440657

In PSv4+ you can enlist the help of the .Where() collection "operator" to determine all invalid values:

Here's a simplified example:

# Sample input.
$string = '10, no, 20, stillno, -1'

# Split the list into an array.
$codes = ($string.Split(',')).Trim()

# Test all array members with a script block passed to. Where()  
# As usual, $_ refers to the element at hand.
# You can perform whatever validation is necessary inside the block.
$invalidCodes = $codes.Where({ $null -eq ($_ -as [int]) })

$invalidCodes # output the invalid codes, if any

The above yields:

no
stillno

Note that what .Where() returns is not a regular PowerShell array ([object[]]), but an instance of [System.Collections.ObjectModel.Collection[PSObject]], but in most situations the difference shouldn't matter.


A PSv2-compatible solution is a bit more cumbersome:

# Sample input.
$string = '10, no, 20, stillno, -1'

# Split the list into an array.
# Note: In PSv*3* you could use the simpler $codes = ($string.Split(',')).Trim() 
#       as in the PSv4+ solution.
$codes = foreach ($code in $string.Split(',')) { $code.Trim() }

# Emulate the behavior of .Where() with a foreach loop:
# Note that do you get an [object[]] instance back this time.
$invalidCodes = foreach ($code in $codes) { if ($null -eq ($code -as [int])) { $code } }

Upvotes: 1

Related Questions