Soru Neden bir foreach nesnesinde mola gibi davranmaya devam ediyor?


Bir powershell komut dosyasında aşağıdakileri yaparsam:

$range = 1..100 
ForEach ($_ in $range){
    if ($_ % 7 -ne 0 ) { continue; }
    Write-Host "$($_) is a multiple of 7"
}

Beklenen çıktısını aldım:

7 is a multiple of 7
14 is a multiple of 7
21 is a multiple of 7
28 is a multiple of 7
35 is a multiple of 7
42 is a multiple of 7
49 is a multiple of 7
56 is a multiple of 7
63 is a multiple of 7
70 is a multiple of 7
77 is a multiple of 7
84 is a multiple of 7
91 is a multiple of 7
98 is a multiple of 7

Ancak, bir boru hattı kullanırsam ve ForEach-Object, devam etmek boru hattı döngüsünden kopuyor gibi görünüyor.

1..100 | ForEach-Object {
    if ($_ % 7 -ne 0 ) { continue; }
    Write-Host "$($_) is a multiple of 7"
}

Benim sorularım, hala ForEach-Object yaparken hala bir davranış gibi devam edebilir miyim, bu yüzden benim boru hattımı parçalamak zorunda değil miyim?


97
2017-10-13 20:24


Menşei


Burada kullanabileceğiniz çok fazla komut içeren bir sayfa var. foreach: techotopia.com/index.php/... - bgmCoder
İyi bir açıklama yaptı ve burada örnek ... powershell.com/cs/blogs/tips/archive/2015/04/27/... - Nathan Hartley


Cevaplar:


Sadece kullan return onun yerine continue. Bu return tarafından çağrılan komut satırından döndürür ForEach-Object belirli bir iterasyonda, böylece, simüle eder continue bir döngüde.

1..100 | ForEach-Object {
    if ($_ % 7 -ne 0 ) { return }
    Write-Host "$($_) is a multiple of 7"
}

Refactoring'de akılda tutulması gereken bir tuhaflık var. Bazen biri dönüştürmek ister foreach deyimi bir boru hattına ForEach-Object cmdlet (hatta diğer adı var foreach Bu, bu dönüşümü kolaylaştırmaya ve hataları kolaylaştırmaya yardımcı olur. Herşey continue ile değiştirilmelidir return.

Not; Ne yazık ki, simüle etmek kolay değil break içinde ForEach-Object.


128
2017-10-14 06:07



OP'nin görünüşte ne söylediği continue simüle etmek için kullanılabilir break içinde ForEach-Object :) - Richard Hauer
@ Richard Hauer Böyle bir continue tüm senaryoyu kırmayacak, sadece ForEach-Object nerede kullanılır. - Roman Kuzmin


Çünkü For-Each Nesne bir cmdlet'tir ve bir döngü değildir ve devam / ara uygulanmaz.

Örneğin, eğer varsa:

$b = 1,2,3

foreach($a in $b){

$a | foreach { if($_ -eq 2) {continue;} else {write-host $_} }

write-host "after"

}

çıktı olarak alacaksınız:

1
after
3
after

Çünkü devam, foreach nesnesi cmdlet'ine değil, foreach döngüsüne uygulanır. Bir döngünün yokluğunda, en dış seviye, bu yüzden size bir mola gibi davranma hissi veriyor.

Peki nasıl davranmaya devam edersiniz? Bir yolu nerede-nesne ofcourse:

1..100 | ?{ $_ % 7  -eq 0} | %{write-host $_ is a mutliple of 7}

16
2017-10-13 20:51



Where-Object cmdlet'in kullanılması iyi bir öneridir. Benim asıl durumumda, if ifademden önce gelen çok sayıda kod satırını okunması zor bir uzun kod satırı haline getirmenin mantıklı olduğunu düşünmüyorum. Ancak, bu benim için başka durumlarda çalışırdı. - Justin Dearing
@JustinDearing - In my actual case, I don't think it makes sense to make the multiple lines of code preceding my if statement into a single long line of hard to read code. Ne demek istiyorsun? - manojlds
@manojlds belki bir satır çözümünüzün "okumak zor" olduğunu düşünüyor, en azından benim için tam tersini tamamlıyor. İşleri yapmak için boru hattı yolu gerçekten güçlü ve açık ve bunun gibi basit şeyler için doğru bir yaklaşım. Kabuğun kodundan faydalanmadan kod yazmak anlamsızdır. - mjsr
Benim durumumda bu doğru cevaptı, devam etmekte olduğum veya geri döneceğim nesneleri filtrelemem için bir koşul ekliyorum, böylece onları ilk sırada işlemem gerekmeyecek. +1 - Chris Magnuson


Başka bir seçenek de kesmek gibidir, ancak bloğunuzu bir kez yürütecek bir döngü içinde sarabilirsiniz, böylece devam etmek istenen etkiye sahip olacaktır:

1..100 | ForEach-Object {
    for($cont=$true;$cont;$cont=$false){
        if ($_ % 7 -ne 0 ) { continue; }
        Write-Host "$($_) is a multiple of 7"
        }
}

3
2017-10-13 21:05



Açıkçası, bu çirkin :) Ve sadece bir kesmek değil, çünkü foreach nesnesi yerine, bir foreach döngüsü kullanmış olabilirsiniz. - manojlds
@manojlds: 1..100 sadece örnek içindir. do {} while ($ False), döngü ve biraz daha sezgisel olduğu kadar çalışır. - Harry Martyrossian


Basit bir başka ifade, olduğu gibi çalışır

1..100 | ForEach-Object {
    if ($_ % 7 -ne 0 ) { 
        #do nothing
    } else {
        Write-Host "$($_) is a multiple of 7"
    }
}

veya tek bir boru hattında

1..100 | ForEach-Object { if ($_ % 7 -ne 0 ) {} else {Write-Host "$($_) is a multiple of 7"}}

ama daha zarif bir çözüm testinizi tersine çevirmek ve sadece başarılarınız için çıktı üretmek

1..100 | ForEach-Object {if ($_ % 7 -eq 0 ) {Write-Host "$($_) is a multiple of 7"}}

0
2017-07-01 00:26