Link to home
Start Free TrialLog in
Avatar of illtbagu
illtbagu

asked on

Testing for a known value that may or may not exist among other unknown values in an array.

I have 4 possible scenarios listed below (a-d) for my arrary that I must test for and take action. The values in this array are an object. The only value in my arrary that is a known value is number 2 which might not exist. This is the part where I am failing and its scenario b, the rest I have working. In other words values 1,3,4,5 could be anything including null and value 2 either exists or it's null. So when running scenario b. my end result should look like this:
delete 1
delete 3
delete 4
delete 5
create 2

------------------------------
a. $objects = 1,2,3,4,5
b. $objects = 1,3,4,5
c. $objects = ""
d. $objects = ,2

if scenario a. then "delete 1,3,4,5 and leave 2 alone"
if scenario b. then "delete 1,3,4,5 and create 2"
if scenario c. then "nothing exists, create 2"
if scenario d. then "2 exists 1,3,4,5 do not exist, do nothing"
foreach ($foo in $objects)
{
if ($foo -ne 2 -and $foo -ne "") {Write-Host delete $foo}
elseif ($foo -eq 2) {Write-Host "$foo exists do nothing"}
elseif ($objects -eq "") {Write-Host "nothing exists, create 2"}
}

Open in new window

SOLUTION
Avatar of Michel Plungjan
Michel Plungjan
Flag of Denmark image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
ASKER CERTIFIED SOLUTION
Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
I do not do Powerscripting but I think you mean


$Create2 = $True
foreach ($foo in $objects)
{
  if ($foo  -ne 2 -and $foo -ne "") {Write-Host delete $foo}
  elseif ($foo -eq  2) {Write-Host "2 exists do nothing"; $Create2 = $False}
}
if  ($Create2) { Write-Hosts "nothing exists, create 2" }


Sure, that would do, the last elseif statement is a bit odd anyway :)

Chris
Avatar of illtbagu
illtbagu

ASKER

Chris-Dent,
You say that that is not what I asked it (my script) to do and you are correct, the
elseif ($objects -eq "") {Write-Host "nothing exists, create 2"}
statement is for scenario c. not b., I did not created any rules for b when the number 2 is missing.
However if I use your flag suggestin then yes I will need to take this out.
I have also looked at hash tables as you suggested but failed to find the contains method, can you give me an example? The below code works and uses a flag however the first foreach that sets the flag sets it each time a non 2 is encountered. How can I using a loop search each value for the number 2 and only set the flag once. So for scenario a. the first foreach sets the flag to true because the last record it finds is the number 5, then in the last foreach loop you change the flag to false if the number 2 is found. There has got to be a cleaner way to do this.

foreach ($foo2 in $objects)
{
if ($foo2 -ne 2 -or $foo2 -eq "") {$Create2 = $True; Write-Host flag to create 2}
}
$Create2

foreach ($foo in $objects)
{
  if ($foo -ne 2 -and $foo -ne "") {Write-Host delete $foo}
  elseif ($foo -eq 2) {Write-Host "$foo exists do nothing"; $Create2 = $False}
  #elseif ($objects -eq "") {Write-Host "nothing exists, create 2"}
}
if ($Create2) { Write-Host "create 2" }
Erm


$Create2 = $True <<<<< 2 not encountered yet
foreach ($foo in $objects)
{
   if ($foo  -ne 2 -and $foo -ne "") {Write-Host delete $foo} <<<<<<  delete any non-2
  elseif  ($foo -eq  2) {Write-Host "2 exists do nothing"; $Create2 = $False} <<<< only set if 2 is encountered
}
if   ($Create2) { Write-Hosts "nothing exists OR 2 did not exist, create 2" } <<<<<<<<<<< we need to create 2 if it was not there either because the object were empty or because 2 did not exist in objects

The Hash example, this may not be the cleanest (because a hash consists of key/value pairs):

$Hash = @{1 = ""; 3 = ""; 4 = ""}
If (!$Hash.Contains(2)) { "2 did not exist, create 2" }

This is the ArrayList example, might be the better choice:

$ArrayList = New-Object Collections.ArrayList
$ArrayList.AddRange(@(1, 3, 4, 5))
If (!$ArrayList.Contains(2)) { "2 did not exist, create 2" }

> a. the first foreach sets the flag

Why would you repeat the ForEach loop?

You must set something that can exist outside of the loop to determine if a value exists. That something must be reset if it is stored as a persistent variable (as I did in my original example) and you intend to call the loop again.

You cannot perform the reset within the loop because you are trying to determine if a value exists within the array as a whole. Inside the loop you can only examine the current element. Take a quick look at this loop from your post above:

$Create2 = $False  # This is the start condition for Create2 before enumerating the array
foreach ($foo2 in $objects)
{
  # Here we have a single value in the array
  if ($foo2 -ne 2 -or $foo2 -eq "") {
    # If the *current* value is not 2 *or* is equal to a space
    $Create2 = $True; Write-Host flag to create 2
  }
}
$Create2

First $foo2 -eq "" is pointless in this context. If the value is a space then it is already not equal to 2.

If $objects contains anything other than 2 anywhere in the array then you set $Create2 to True, regardless of whether or not it finds 2 elsewhere in the array. Test it with $objects = 1, 2.

If resetting the flag each time is undesirable then you can wrap the whole thing up in a function:

Function DoesArrayContain2 ([Array]$Array)
{
  ForEach ($Value in $Array)
  {
    If ($Value -eq 2) { Return $True }
  }
  Return $False
}

And you might use that to test your array:

$objects = 1,2,3,4,5
DoesArrayContain2 $objects
$objects = 1,3,4,5
DoesArrayContain2 $objects

It achieves the same as my original use of the flag, except this time the default value is False and is forced if the loop exits without finding 2 first.

Chris
I have another for you.

PowerShell is a .NET language. The types we're dealing with are .NET types. Object[] is System.Object[] and has a base type of System.Array. It means a mass of static methods from System.Array can be applied here:

http://msdn.microsoft.com/en-us/library/system.array_members%28v=VS.100%29.aspx

And means you can do this:

$objects = 1, 2
If ([Array]::IndexOf($objects, 2) -eq -1) { "2 did not exist, create 2" }
$objects = 1, 3
If ([Array]::IndexOf($objects, 2) -eq -1) { "2 did not exist, create 2" }

If the value does exist it will return the element number in the array (0 or higher).

> There has got to be a cleaner way to do this.

And I wanted to catch up on this one.

Can you give us context for the loop you're trying to use?

It's not unusual to come up with one method of doing something in PowerShell only to find something far easier later on.

In the unlikely event you can't deal with it using PowerShell CmdLets you can start hunting through the .NET framework for a way. The static method I used above is an example of this ([Array]::IndexOf).

For us to help you find a better way you'll have to tell us how you're creating $objects and what your goals are.

Don't get me wrong, I won't stop this discussion if you wish to continue. I'll quite happily spend days discussing the loops above with you and mplungjan, it's fun (well, for me at least) if you want to learn it :)

Chris
Great thanks Chris-Dent. I think I like the array list method. You have been very helpful!!
Also thanks to mplungjan and mplungjan
Someone slap me for making this harder than it needed to be : )

You're most welcome.

But I don't think slapping is called for, if you never learnt the hard way how would you ever know the easy way was easy? :)

Chris