0

I need to determine whether all elements of an array are exactly the same. I'd like this to play nice with all data-types as well, Object/String/Int/etc.

Is there an easy way to do this in PowerShell?

function Test-ArrayElementsEqual {
    [CmdletBinding()]
    param (
        [Parameter(Mandatory,Position = 0,ValueFromPipeline)]
        [object]
        $Array,
    )

    $test = $null
    foreach ($item in $Array) {
        if(!$test){
            $test = $item
            continue
        }
        if($test -ne $item){
            return $false
        }
    }
    return $true
}

This is what I have now, but I have a feeling it's a broken implementation, and that there is something more elegant.

Any help would be great.

Edit:


I put together a pretty good utility function for this since last posting. It supports objects, arrays, all numerical data-types, XML, etc.

Here's the code:

https://github.com/visusys/VSYSUtility/blob/main/Public/Test-ObjectContentsAreIdentical.ps1

fmotion1
  • 237
  • 4
  • 12
  • 1
    this `[bool]($NotAllSame.Where({$_ -ne $NotAllSame[0]}))` will give you `True` ... and this `[bool]($AllSame.Where({$_ -ne $AllSame[0]}))` will give you `false`. ///// you can change the comparison operator to reverse the true/false result. – Lee_Dailey Nov 22 '21 at 01:37
  • What do you mean by _exactly the same_ ? Same value or same type or both ? – Santiago Squarzon Nov 22 '21 at 01:38
  • I meant both, if at all possible. Originally I only needed this to compare arrays of strings, but I decided to write a helper function that could cover all my bases. – fmotion1 Nov 22 '21 at 01:40
  • @Lee_Dailey does that work for objects as well? It can't be that simple, can it? – fmotion1 Nov 22 '21 at 01:40
  • When you say `objects` do you mean all properties of this object are the same and hold the same value as all the other properties and values of the objects of a given array? You need to be more specific – Santiago Squarzon Nov 22 '21 at 01:42
  • @SantiagoSquarzon that's a good question. I think a switch would work, if enabled it would only validate all object properties as the same without regard to values. If disabled it would check for true equality across both properties *and* values – fmotion1 Nov 22 '21 at 01:45
  • Shouldn't be `Compare-Object` suitable for this job? – Olaf Nov 22 '21 at 02:21
  • If you're looking to compare if complex objects within an array are the same then there is "no easy implementation". If you want to compare if an array holds the same values and / or the elements are of the same type then Lee_Dailey has given you a good hint you just need to include a type comparison. – Santiago Squarzon Nov 22 '21 at 02:26
  • @SantiagoSquarzon Do you know of a way to compare complex objects? I've got Lee's code working fine, but it's not triggering for objects correctly. I have three identical objects and it's saying they aren't unique. I'll take any complex solution you can throw at me. I really need this functionality. – fmotion1 Nov 22 '21 at 03:00

1 Answers1

2

As in my comment, for simple comparisons you can use what Lee_Dailey proposed in his comment only adding a type comparison which can be accomplished by the use of .GetType() method.

This function will return $true if all elements are of the same type and same value and will return the index and expected value / type of the first element that is not of the same type or does not have the same value.

function Test-ArrayElementsEqual {
[CmdletBinding()]
param (
    [Parameter(Mandatory)]
    $InputObject
)
    begin
    {
        $refVal = $InputObject[0]
        $refType = $refVal.GetType()
        $index = 0
    }

    process
    {
        foreach($element in $InputObject)
        {
            if($element -isnot $refType)
            {
                "Different Type at Position $index. Expected Type was {0}." -f $refType.FullName
                return
            }
            if($element -ne $refVal)
            {
                "Different Value at Position $index. Expected Value was $refVal."
                return
            }

            $index++
        }

        $true
    }
}

Test Examples

$arr1 = 123, 123, '123'
$arr2 = 123, 345, 123
$arr3 = 'test', 'test', 'test'

Results

PS /> Test-ArrayElementsEqual $arr1
Different Type at Position 2. Expected Type was System.Int32.

PS /> Test-ArrayElementsEqual $arr2
Different Value at Position 1. Expected Value was 123.

PS /> Test-ArrayElementsEqual $arr3
True

If you're looking for a way of comparing if different objects are the same you might find useful information on the answers of this question: Prevent adding pscustomobject to array if already exists

Santiago Squarzon
  • 41,465
  • 5
  • 14
  • 37
  • 1
    Thank you for this. The function looks great. However I really need a way to compare objects (PSCustom, .NET Lists, etc). I don't care how complex the implementation, I would be overjoyed if you had a solution for that as well. Sorry if I'm asking too much. I can make another post if so. – fmotion1 Nov 22 '21 at 03:04
  • @Jay see my last edit, you might find something useful looking at the answers on that question. – Santiago Squarzon Nov 22 '21 at 03:08
  • Thanks! I'll look through it. Check out this Gist: https://gist.github.com/visusys/9ee4bcb393e98c6fa71e878d39f4951a - The code really doesn't like me passing in PSCustomObjects. – fmotion1 Nov 22 '21 at 03:10
  • @Jay you're using the argument `-$InputObject` which is not valid, it should be `-InputObject`. In addition, as I mentioned before, this function will not work to compare those objects. – Santiago Squarzon Nov 22 '21 at 03:15
  • @Jay no problem, happy to help. if you're looking to compare objects of different types you might want to add another question, though, I don't think it's a simple implementation (as you might have seen from the answers of my linked question) and more so if you want the code to differentiate different types of objects. – Santiago Squarzon Nov 22 '21 at 03:24
  • 1
    Nice. If you define `$refType` as `$refType = $InputObject[0].GetType()`, you can more simply use `$element -isnot $refType` – mklement0 Nov 22 '21 at 03:25
  • Yeah, I read through that entire thread and TBH I am in way over my head. I can see how it would be applicable to my situation, but I'm too dumb to figure out an implementation. I have yet to even touch classes (but open to trying it out). What I want is object support that looks at key/value sets being equal. And then basing equality on that. If anyone at all can help me here I would be eternally grateful. – fmotion1 Nov 22 '21 at 03:27
  • 1
    Good point @mklement0, thanks. I was gonna tell OP that your proposed answer on my linked question (serializing the objects he needs to compare) might work for his use case though I'm not sure if this would work for any type of object. He might be better of asking a new question with his specific use case. In any case, thanks for the feedback! – Santiago Squarzon Nov 22 '21 at 03:29
  • Also, one more question, what is the index value for in your function for? – fmotion1 Nov 22 '21 at 03:41
  • @Jay to help you identify the position of the element on the array that failed the comparison, i.e. on the second example it says `at Position 1`, which can translate to `$arr2[1]` to inspect that element. – Santiago Squarzon Nov 22 '21 at 03:44
  • 1
    I just wanted to update, I put together a pretty robust solution: https://github.com/visusys/VSYSUtility/blob/main/Public/Test-ObjectContentsAreIdentical.ps1 Working great for me over here, with object support as well. Going to update it with more content types as well soon. – fmotion1 Nov 28 '21 at 00:29