15

I'm having some troubles with nested ForEach loops in Powershell. First, I need to iterate through list 1. For every object in list 1, I need to iterate through list 2. When I found the resembling object in list 2, I want to go to the next object in list 1.

I've tried break, i've tried continue, but it won't work for me.

Function checkLists() {
  ForEach ($objectA in $listA) {
    ForEach ($objectB in $listB) {
       if ($objectA -eq $objectB) {
           // Do something 
           // goto next object in list A and find the next equal object
       }
    }
  }
}

a) What does a break/continue exactly do in PowerShell?

b) How exaclty should I conquer my 'problem'?

1
  • Break works the same as in C, C++. C# etc and it's definitely the solution for yout problem - just put break after "Do something statement" in inner loop. PS: you should use # for "comments". Commented Jul 28, 2017 at 10:29

4 Answers 4

11

Use a label as described in get-help about_break:

A Break statement can include a label. If you use the Break keyword with
a label, Windows PowerShell exits the labeled loop instead of exiting the
current loop

Like so,

foreach ($objectA in @("a", "e", "i")) {
    "objectA: $objectA"
    :outer
    foreach ($objectB in @("a", "b", "c", "d", "e")) {
       if ($objectB -eq $objectA) {
           "hit! $objectB"
           break :outer
       } else { "miss! $objectB" }
    }
}

#Output:
objectA: a
hit! a
objectA: e
miss! a
miss! b
miss! c
miss! d
hit! e
objectA: i
miss! a
miss! b
miss! c
miss! d
miss! e
Sign up to request clarification or add additional context in comments.

4 Comments

There's a couple of things wrong here. The break :outer as used here seems to do absolutely nothing different than break without any labels. Actually the documentation help about_Break says to place the label before the loop you wish to exit, like so: :outer foreach(.... But you know what? Even this doesn't seem to do anything at all to code execution. I'm talking PowerShell v4. Is this feature broken or what?
The label after break (and continue aswell) has to be written without the leading colon ":", otherwise it won't work.
I agree with IfediOkonkwo and rotsch. Solution works but label haven't effect in this case. Like said @rotsch label has to be written without ':' (ie break outer) and has to be placed before breaked loop. If you place label before first loop, you get 'hit! a' only. Nothing more! That means than break exits labeled (first in this case, second in vonPryz incorrect case) loop. Anyway +1 for information about "label in break" devil's functionality :).
"outer" actually is labeling the inner loop. Therefore the "break :outer" works exactly like a break, and you should not put colon after the break keyword. I submitted and edit on the answer to fix it.
5

Here's an example using break/continue. Reverse the test in the inner loop, and use Continue to keep the loop going until the test fails. As soon as it gets a hit, it will break the inner loop, and go back to the next object in the outer loop.

foreach ($objectA in @("a", "e", "i"))
   {
    "objectA: $objectA"
    foreach ($objectB in @("a", "b", "c", "d", "e")) {
       if ($objectB -ne $objectA)
         {
           "miss! $objectB"
           continue
         }
     else {
           "hit!  $objectB" 
           break
          }
   }
}

objectA: a
hit!  a
objectA: e
miss! a
miss! b
miss! c
miss! d
hit!  e
objectA: i
miss! a
miss! b
miss! c
miss! d
miss! e

Comments

1

I would use a Do..until loop - its intended use is exactly what you're describing.

Function checkLists() {
  ForEach ($objectA in $listA) {
    $Counter = 0
    Do {
        $ObjectB = $listB[$Counter]
        #other stuff
    }
    #Keep going until we have a match or reach end of array
    Until (($objectA -eq $objectB) -or (($Counter+1) -eq $Listb.count()))
    }
}

Here's an easy example:

#Example use of do..until
$i = 1
do {
  $i++
  write-host $i
  }
until ($i -eq 10)

Comments

-1

This one took me awhile to finally get it correct. Hope the solution and the example help other folks.

In this app, I need to process each node and subnode as nested loops. The key seems to be getting the relative node names in the foreach loop.

Here's the code:

[System.Xml.XmlDocument] $xml = new-object System.Xml.XmlDocument;
$xml.load("g:\tmp\down\order_01.xml");

foreach ( $order in $xml.SelectNodes("//orders/order"))
{
    # all these work
    $invoiceNumber = $xml.orders.order."invoice-no";                 
    $invoiceNumber = $order."invoice-no";                            
    $invoiceNumber = $order.SelectSingleNode("//invoice-no");        
    $invoiceNumber = $order.SelectSingleNode("./invoice-no");        
    $invoiceNumber = $order.SelectSingleNode("invoice-no");          

    foreach ($lineItem in $order.SelectNodes("product-lineitems/product-lineitem"))   #$xml.orders.order.'product-lineitems'.'product-lineitem')
    {
        $tax = $lineItem.tax;                             #works
        $tax = $lineItem.SelectSingleNode("tax");         #also works

        $name = $lineItem."product-name";
        write-host "Tax ", $tax, " name ", $name;

        foreach ( $optionItem in $lineItem.SelectNodes("option-lineitems/option-lineitem"))
        {
            $optionTax = $optionItem."tax";
            $optionId  = $optionItem."option-id";
            if ($optionId -eq 'engravingOption')
            {
#                $optionTax = $optionItem.SelectSingleNode("tax");
                Write-Host  "option Tax ",  $optionTax, " option id ", $optionId;
            }
        }
    }
}


And here is the sample xml:


<?xml version="1.0" encoding="UTF-8"?>      
<orders>xmlns="http://www.demandware.com/xml/impex/order/2006-10-31">
    <order order-no="00030562">     
        <invoice-no>00038012</invoice-no>   
        <product-lineitems> 
            <product-lineitem>      
                <tax>13.45</tax>    
                <product-name>Scoop Ice Bucket</product-name>       
                <option-lineitems>  
                    <option-lineitem>       
                        <net-price>7.00</net-price> 
                        <tax>11.11</tax>     
                        <option-id>includeGiftWrapping</option-id>  
                    </option-lineitem>      
                </option-lineitems> 
            </product-lineitem>     
            <product-lineitem>      
                <tax>22.22</tax>     
                <product-name>Love Bowl</product-name>      
                <option-lineitems>  
                    <option-lineitem>       
                        <tax>33.33</tax>     
                        <option-id>includeGiftWrapping</option-id>  
                    </option-lineitem>      
                    <option-lineitem>       
                        <tax>44.44</tax>     
                        <option-id>includeGiftWrapping</option-id>  
                    </option-lineitem>      
                </option-lineitems> 
            </product-lineitem>     
            <product-lineitem>      
                <tax>55.55</tax>    
                <product-name>Groove Decanter Set</product-name>    
                <option-lineitems>  
                    <option-lineitem>       
                        <tax>66.66</tax>     
                        <option-id>includeGiftWrapping</option-id>  
                    </option-lineitem>      
                </option-lineitems> 
            </product-lineitem>     
            <product-lineitem>      
                <tax>66.66</tax>     
                <lineitem-text>Klasp Cocktail Shaker</lineitem-text>
                <option-lineitems>  
                    <option-lineitem>       
                        <tax>77.77</tax>     
                        <option-id>includeGiftWrapping</option-id>  
                    </option-lineitem>      
                    <option-lineitem>       
                        <tax>88.88</tax>     
                        <option-id>engravingOption</option-id>      
                    </option-lineitem>      
                </option-lineitems> 
            </product-lineitem>     
        </product-lineitems>
    </order>
</orders>      

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.