【问题标题】:Nested ForEach() in PowerShellPowerShell 中的嵌套 ForEach()
【发布时间】:2014-01-18 08:20:41
【问题描述】:

我在使用 Powershell 中的嵌套 ForEach 循环时遇到了一些问题。首先,我需要遍历列表 1。对于列表 1 中的每个对象,我都需要遍历列表 2。当我在列表 2 中找到相似对象时,我想转到列表 1 中的下一个对象。

我试过休息,我试过继续,但它对我不起作用。

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) PowerShell 中的中断/继续究竟做了什么?

b) 我应该在多大程度上解决我的“问题”?

【问题讨论】:

  • Break 的工作方式与 C、C++ 中的相同。 C# 等,它绝对是你问题的解决方案 - 只需在内循环中的“做某事声明”之后放置 break。 PS:你应该使用#来表示“cmets”。

标签: powershell foreach break


【解决方案1】:

使用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

这样,

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

【讨论】:

  • 这里有一些问题。这里使用的break :outer 似乎与没有任何标签的break 完全不同。实际上,关于_Break 的文档帮助说将标签放在您希望退出的循环之前,如下所示::outer foreach(...。但你知道吗?即使这似乎对代码执行也没有任何作用。我说的是 PowerShell v4。这个功能是坏了还是什么?
  • break(和continue)后的标签必须不带前导冒号“:”,否则不起作用。
  • 我同意 IfediOkonkwo 和 rotsch。解决方案有效,但在这种情况下标签无效。就像说的@rotsch 标签必须写没有':'(即外部中断)并且必须放在中断循环之前。如果你在第一个循环之前放置标签,你会得到'命中!一个'只有。而已!这意味着比 break 退出标记(在这种情况下是第一个,在 vonPryz 不正确的情况下是第二个)循环。无论如何 +1 有关“标签中断”魔鬼功能的信息:)。
  • "outer" 实际上是标记内部循环。因此,“break :outer”的工作方式与 break 完全一样,您不应该在 break 关键字后面加上冒号。我提交并编辑了答案以修复它。
【解决方案2】:

这是一个使用中断/继续的示例。反转内部循环中的测试,并使用 Continue 保持循环继续进行,直到测试失败。一旦它被击中,它将打破内循环,并返回到外循环中的下一个对象。

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

【讨论】:

    【解决方案3】:

    我会使用 Do..until 循环 - 它的预期用途正是您所描述的。

    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()))
        }
    }
    

    这是一个简单的例子:

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

    【讨论】:

      【解决方案4】:

      这个我花了一段时间才终于把它弄对了。希望解决方案和示例对其他人有所帮助。

      在这个应用程序中,我需要将每个节点和子节点作为嵌套循环处理。关键似乎是在 foreach 循环中获取相对节点名称。

      代码如下:

      [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>      
      

      【讨论】:

        猜你喜欢
        • 2021-10-06
        • 2023-03-21
        • 2010-11-18
        • 2017-05-09
        • 1970-01-01
        • 2018-03-07
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多