Bir for-loop içinde, eğer mümkünse, mola durumunu koşul alanına taşımalı mıyım? [kapalı]


48

Bazen böyle bir mola gerektiren döngülere ihtiyacım var:

for(int i=0;i<array.length;i++){
    //some other code
    if(condition){
        break;
    }
}

Yazarken kendimi rahatsız hissediyorum

if(condition){
    break;
}

çünkü 3 satır kod tüketiyor. Ve ben döngü olarak yeniden yazılabilir buldum:

                                   ↓
for(int i=0;i<array.length && !condition;i++){
    //some other code
}

Öyleyse benim sorum şu, eğer mümkünse kod satırlarını azaltmak için koşulu koşul alanına taşımak iyi bir uygulama mıdır?


7
Özel olanın ne olduğuna conditionbağlı.
Bergi

4
Misra'nın döngüler içerisinde "ara vermeyi" ve "devam etmeyi" yasaklamasının bir nedeni var. Ayrıca bakınız: stackoverflow.com/q/3922599/476681
BЈовић

35
Satır sayısının kendisinin asıl mesele olmadığını düşünüyorum. Tek satırda yazılabilir. if (durum) sonu; Bence sorun okunabilirlik. Şahsen döngü koşulu kullanmaktan başka bir döngü kırmak hoşuma gitmiyor.
Joe,

97
Çünkü herhangi bir stilden hoşlanmamak için 3 satır A kodunu tüketir . IMO "kod satırlarını tüketiyor" alakasız ve iyi bir şey arasında bir yerdedir. Çok az satırın içine çok fazla mantık doldurmaya çalışmak, okunamayan kodlara ve bulunması zor hatalara neden olur.
Andrew Henle,

3
Muhtemelen popüler olmayan görüş: for(int i=0;i<array.length && !condition;i++)nispeten nadirdir ve sadece kodu gözden geçiren biri tarafından göz ardı edilebilir; bu , döngü tanımında daha çok çoklu kırılma koşullarına sahip olan bir whileveya do whiledöngü için iyi bir kullanım durumu olabilir .
Jules,

Yanıtlar:


154

Verdiğiniz bu iki örnek işlevsel olarak eşdeğer değil. Orijinalde, durum testi "başka bir kod" bölümünden sonra yapılır, oysaki değiştirilmiş versiyonda, ilk önce döngü gövdesinin başlangıcında yapılır.

Kod asla satır sayısını azaltmak amacıyla yeniden yazılmamalıdır. Açıkçası, bu şekilde çalıştığında güzel bir bonus, ancak hiçbir zaman okunabilirlik veya doğruluk pahasına yapılmaması gerekir.


5
Duygunuzu anlıyorum, ancak döngünün birkaç yüz satır uzunluğunda ve birden çok koşullu ara verilmiş olduğu yerlerde yeterince eski kod kullandım. Kodun beklediğiniz koşullu araya girmesini beklediğinizde hata ayıklamayı çok zorlaştırır, ancak önce kullanılan kod ilk önce koşullu aradır. Bu kodu nasıl idare ediyorsunuz? Yukarıdakilere benzer kısa örneklerde, çok yaygın senaryoların bu şekilde unutulması kolaydır.
Berin Loritsch

84
@BerinLoritsch: Bununla baş etmenin doğru yolu, birkaç yüz satır uzunluğundaki döngülere sahip olmamak!
Chris,

27
@Walfrat: Yeniden yazmak bir seçenek değilse, o zaman artık bir soru yok. Temel yöntem döngüsünü kısaltması ve umarım mantık akışını daha açık hale getirmesi gereken kod bloklarını hareket ettirmek için genellikle "Extract Method" tipi bir refactor kullanabileceğinizi söylemiştiniz. Bu gerçekten durumdan bir durumdur. Kısa yöntemleri tutmanın benim genel kural stand by ve kesinlikle İslam'ın başkanıdır döngü mantık kısa tutmak ama genel anlamda bundan daha bir şey söylemek için denemek istemiyorum edeceğiz gerçi ...
Chris

4
@AndrewHenle kısalıklığı okunabilirliktir, en azından artan ayrıntı seviyesinin her zaman okunabilirliği ve bakım edilebilirliği azaltması anlamında . LOC'nin azaltılması, yoğunluğun arttırılması ve soyutlama seviyesinin yükseltilmesi ile elde edilir ve bu sahadaki diğer Q / A çiftlerinde belirtildiği gibi sürdürülebilirlik ile çok sıkı bir şekilde ilişkilidir.
Leushenko

5
@Joe bir Do-While inşası o kadar nadirdir ki, daha sonra bu kodu sürdürmesi gereken geliştiricilere yol açma eğilimi gösterir. Bir kaç dev aslında onları görmedi! Bir süre-ebilmek daha iyi okunabilirliği geliştirmek eğer emin değilim - eğer bir şey varsa , kodu anlamak için zorluk artacaktır . Örnek olarak - mevcut kod tabanım yaklaşık 15 yaşında ve yaklaşık 2 milyon LOC'ye sahip. Yaklaşık elli geliştirici zaten dokundu. Tamamen sıfır do-while döngüsü var!
T. Sar - Monica

51

"3 satır kod tüketiyor" argümanı almıyorum ve bu nedenle kötü. Sonuçta, sadece şöyle yazabilirsiniz:

if (condition) break;

ve sadece bir satır tüketin.

Eğer ifdöngü yoluyla yarım görünür, tabii ki ayrı bir test olarak varolması gerekir. Ancak, bu test bloğun sonunda görünüyorsa, döngünün her iki ucunda da devam testine sahip olan ve muhtemelen kodun karmaşıklığına eklenmiş bir döngü oluşturdunuz. Yine de, bazen if (condition)testin yalnızca blok yürütüldükten sonra mantıklı olabileceğini unutmayın.

Ancak, bunun başka bir yaklaşımı benimseyerek, böyle olmadığını varsayalım:

for(int i=0;i<array.length && !condition;i++){
    //some other code
}

Çıkış koşulları bir arada tutulur ve bu durum işleri basitleştirebilir (özellikle " başka bir kod " uzunsa).

Elbette burada doğru cevap yok. Bu nedenle, dilin deyimlerinin, ekibinizin kodlama sözleşmelerinin vs. ne olduğunun farkında olun.


14
@ jpmc26, Daha İyi? Hayır. Geçerli alternatif tarz? Tabii ki.
David Arno

6
Kod daha sonra düzenlendiğinde karışması ve daha büyük dezavantajlara maruz kalmaması daha da zor.
jpmc26

4
Onları "döngü içeriği uzun olabilir" nedeniyle bir arada tutmak zayıf bir argüman gibi görünüyor. For içeriğinizin okunması zor olduğunda, iki kod satırını kaydetmekten başka bir sorun yaşarsınız.
BlueWizard

12
@ jpmc26 Katılmıyorum. Parantezler, bu cevaba göre en kısa, tek astar koşullarında gereksiz yığınlardır. Olmadan göze daha zarif ve kolaydır. Üçlü şartlı işleç gibiler. Daha büyük açıklama bloklarına ayırırken parantez eklemeyi asla unutmadım; Sonuçta zaten yeni çizgiler ekliyorum.
benxyzzy

3
Hepsi bir stil tercihi, ancak biri daha güvenli olduğu tartışmasını yaparsa, bu akıl yürütmeye katılmıyorum. Ben kendimi diş
telsiz

49

Bu tür bir soru, neredeyse programlandığı sürece tartışmaya neden oldu. Şapkamı ringe atmak için, breakkoşulu olan sürüme giderdim ve işte bu yüzden (bu özel durum için):

forDöngü döngü içinde yineleme değerleri belirtmek için sadece var. Bunun içindeki kırılma koşulunu kodlamak sadece mantık IMO'sunu karıştırır.

Ayrı olması break, normal işlem sırasında, değerlerin fordöngüde belirtildiği gibi olduğunu ve işlemin , koşulun geldiği yer dışında devam etmesi gerektiğini açıkça göstermektedir.

Bir parça arka plan olarak, kodlamaya başladım break, durumu foryıllarca döngüye koydum (istisnai bir programcının yönetiminde) ve daha sonra breakstile döndüm, çünkü çok daha temiz hissettim (ve geçerli stil kullandığım çeşitli kod tome'leri).

Günün sonunda bu kutsal savaşlardan bir diğeri - bazıları yapay olarak bir döngüden asla kopmamanız gerektiğini söylüyor , yoksa gerçek bir döngü değil. Okunabilir olduğunu düşündüğünüzü yapın (hem kendiniz hem de başkaları için). Tuş vuruşlarını azaltmak gerçekten sizin için ise, hafta sonları golf isteğinize - isteğe bağlı bira.


3
Koşulun "bulunan" gibi iyi bir adı varsa (örneğin, diziyi bir şey için arıyorsunuzdur), o zaman for döngüsünün başına koymak iyi bir fikirdir.
user949300,

1
forDöngülerin, yineleme sayısı bilindiğinde (örneğin, dizilimin / listenin sonundan başka bir koşul olmadığında) ve whilene zaman kullanılmadığı söylendi . Bu bir whiledöngü için durum gibi görünüyor . Okunabilirlik endişe ise, idx+=1döngü içindeki bir if/elsesatır bloktan daha okunaklı olur
Laiv

Bunu izleyen kod varsa, break koşulunu sadece döngüye koyamazsınız, bu yüzden en azından "if (condition) {found = true; devam;};
gnasher729

Biz için kullanılan for(int i=0; i<something;i++)yarım geliştiriciler gerçekten hatırlamıyorum sanırım döngüler fordöngüler farklı kullanılabilir ve böylece zor anlar anlamakta güçlük &&conditionparçasını.
Ralf Kleberhoff

@RalfKleberhoff Gerçekten. Pek çok yeni geliştiricinin, tripart deyimi ifadelerinin isteğe bağlı olması konusunda sürpriz ifade ettiğini gördüm. Son gördüğüm zamanı bile hatırlamıyorum for(;;)...
Robbie Dee

43

fordöngüler 1 üzerinde yineleme içindir - sadece lol-haydi-bazı-rasgele-onlardan-vücuttan-ve-to-on-the-the-the-loop-başlığı-koymak-şeyler değildir - üç ifadeleri çok özel anlamlar:

  • İlki yineleyiciyi başlatmak içindir . Bir indeks, işaretçi, bir yineleme nesnesi veya her neyse - yineleme için kullanıldığı sürece olabilir .
  • İkincisi, sona ulaşıp ulaşmadığımızı kontrol etmek içindir.
  • Üçüncüsü, yineleyiciyi ilerletmek içindir.

Fikir, yineleme işlemlerini ( nasıl yinelemeli) döngü içindeki mantıktan ayırmaktır ( her yinelemede ne yapılır). Çoğu dilde, sizi yinelemenin ayrıntılarından kurtaracak her bir forma sahiptir, ancak dilinizde bu yapı olmasa veya senaryoda kullanılamıyorsa bile - hala döngü başlığını sınırlamanız gerekir. yineleme işleme.

Öyleyse, kendinize sormanız gerekir - yineleme yönetimi veya döngü içindeki mantık hakkındaki durumunuz mu? Muhtemelen, döngü içindeki mantıkla ilgilidir - bu yüzden başlıktan çok döngü içindeki kontrol edilmelidir.

1 Diğer döngüler karşısında, bir şeyin olmasını "beklemektedir". A for/ foreachdöngü yinelenecek öğelerin bir "listesi" kavramına sahip olmalıdır - bu liste tembel ya da sonsuz ya da soyut olsa bile.


5
Bu soruyu okuduğumda ilk düşüncemdi. Hayal kırıklığına uğramış birisinin söylediğini görmek için yarım düzine yanıtı kaydırmam
Nemo

4
Umm ... tüm döngüler yineleme içindir - "yineleme" kelimesi :-) anlamına gelir. "Koleksiyon üzerinde yineleme" veya "yineleyici kullanarak yineleme" gibi bir şey demek istediğinizi varsayıyorum?
psmears

3
@psmears Tamam, belki yanlış kelimeyi seçtim - İngilizce anadilim değil ve yinelemeyi düşündüğümde "bir şeyin üzerinde yinelemeyi" düşünüyorum. Ben cevabı düzelteceğim.
Idan Arye,

Ara durum, durumun olduğu gibi bir şeydir someFunction(array[i]). Şimdi koşulun her iki kısmı da yinelediğiniz şeyle ilgilidir ve bunları &&döngü başlığında birleştirmenin bir anlamı olur .
Barmar

Pozisyonuna saygı duyuyorum ama aynı fikirde değilim. Bence for, kalpteki döngüler bir liste üzerindeki döngüler değil sayıcılardır ve bu fordaha önceki dillerin sözdizimi tarafından desteklenir (bu diller genellikle bir for i = 1 to 10 step 2sözdizimine sahipti ve stepkomut - ilk dizinin dizini olmayan bir başlangıç ​​değerine izin verse bile) element - liste bağlamında değil, sayısal bağlamda ipuçlarını gösterir). Sadece ben destekler düşünüyorum kullanma durumu forsadece bir liste üzerinde yineleme olarak döngüler parallelising edilir ve bu örneğin yapıyor kodu, bir tür kırılmaz için zaten şimdi açık sözdizimi gerektirir.
Logan Pickup

8

İle sürümünü kullanmanızı öneririm if (condition). Daha okunaklı ve hata ayıklamak daha kolaydır. Fazladan 3 kod satırı yazmak parmaklarınızı kırmaz ancak bir sonraki kişinin kodunuzu daha kolay anlamasını sağlar.


1
Ancak (yorum yapıldıysa) döngü bloğu yüzlerce kod satırına sahip değildir ve içindeki mantık roket bilimi değildir. Bence argüman tamam, ama naming thingsne olup bittiğini ve kırılma koşulunun ne zaman gerçekleştiğini anlamak için düzgün bir şeyi özlüyorum .
Laiv,

2
@Laiv Eğer döngü bloğu içinde yüzlerce kod satırı varsa, o zaman sorun kesme koşulunu yazacağımız sorudan daha büyük problemlerdir.
Aleksander

Bu yüzden cevabı bağlamsallaştırmayı önerdim, çünkü her zaman doğru değildir.
Laiv,

8

Belirli öğelerin atlanması gereken bir koleksiyonu yineliyorsanız, yeni bir seçenek öneriyorum:

  • Koleksiyonunuzu yinelemeden önce filtreleyin

Hem Java hem de C #, bunu göreceli olarak önemsiz kılıyor. C ++ geçerli olmayan bazı öğeleri atlamak için süslü bir yineleyici yapmanın bir yolu olsaydı şaşırmam. Ancak, bu yalnızca, seçtiğiniz dil destekliyorsa ve kullanmanızın nedeni, breakbir öğeyi işleyip işlemediğinizle ilgili şartlar olduğu için gerçekten bir seçenektir .

Aksi halde, durumunuzu for döngüsünün bir parçası yapmak için çok iyi bir neden vardır - bunun ilk değerlendirmenin doğru olduğunu varsaymak.

  • Bir döngünün ne zaman erken bittiğini görmek daha kolay

For loop'ınızın birkaç koşulu ve bazı karmaşık matematik işlemlerinin yapıldığı birkaç yüz satır aldığı kod üzerinde çalıştım. Bununla karşılaştığınız sorunlar:

  • break mantık gömülü komutları bulmak zor ve bazen şaşırtıcı
  • Hata ayıklama, neler olduğunu gerçekten anlamak için döngünün her yinelemesinde adım atmayı gerektirir
  • Kodun birçoğu, kolayca yeniden yazılabilir yeniden yapılandırmaya sahip değildir veya yeniden yazma işleminden sonra fonksiyonel denkliği sağlamak için birim testleri yoktur.

Bu durumda tercih sırasına göre aşağıdaki yönergeleri tavsiye ederim :

  • Bir breakmümkünse ihtiyacı ortadan kaldırmak için koleksiyonu filtreleyin
  • For loop koşullarının koşullu bölümünü yapın
  • Koşullu breakolanları mümkünse döngünün üst kısmına yerleştirin
  • Molaya dikkat çeken çok satırlı bir yorum ekleyin ve neden orada?

Bu kurallar her zaman kodunuzun doğruluğuna tabidir . Niyeti en iyi şekilde temsil edebilecek ve kodunuzun netliğini artırabilecek seçeneği seçin.


1
Bu cevabın çoğu iyi. Ancak ... Bir koleksiyonun filtrelenmesinin continueifadelere duyulan ihtiyacı ortadan kaldırabildiğini görebiliyorum, ancak nasıl yardımcı olduklarını anlamıyorum break.
user949300,

1
@ user949300 Bir takeWhilefiltre breakifadeleri değiştirebilir . Bir varsa - örneğin Java sadece Jave 9 (öyle değil onları alır o kendiniz uygulamak zor)
Idan Arye

1
Ancak Java'da yinelemeden önce filtreleme yapabilirsiniz. Akışları kullanarak (1.8 veya üstü) veya Apache Koleksiyonlar'i kullanarak (1.7 veya öncesi).
Laiv,

@IdanArye - Java akışları API'sine (örneğin JOO-lambda ) bu tür olanakları ekleyen kitaplıklar var
Jules

@IdanArye yorumunuzu önce bir takeWhile hiç duymadım. Süzgeci bir siparişte açıkça belirtmek, sıra dışı ve taklit edici bir davranış sergiliyor, çünkü "normal" bir filtrede, her öğe önce veya sonra gelenlerden bağımsız olarak doğru veya yanlış olarak geri dönüyor. Bu şekilde işleri paralel olarak çalıştırabilirsiniz.
user949300

8

Aksi takdirde önemli bir kazanç elde edemediğiniz sürece en az sürpriz yaklaşımını kullanmanızı şiddetle tavsiye ederim .

İnsanlar bir kelimeyi okurken her mektubu okumazlar ve bir kitabı okurken her kelimeyi okumazlar - eğer okumaya yatkınlarsa, kelimelerin ve cümlelerin ana hatlarına bakarlar ve beyninin gerisini doldurmasına izin verirler. .

Bu nedenle, zaman zaman geliştirici bunun bunun döngü için bir standart olduğunu varsayacağına ve buna bakmayacağına dair bir ihtimal olduğunu düşünüyor:

for(int i=0;i<array.length&&!condition;i++)

Ne olursa olsun bu stili kullanmak istiyorsanız, ben parçaları değiştirerek tavsiye for(int i=0;i<ve ;i++)bu döngü için standart olduğunu o okuyucunun beynine söyle.


Birlikte gitmek için başka bir neden de if- breakyaklaşımınızı her zaman for-konisyonla kullanamamanızdır . Kullanmanız gerekir if- breakbreak koşulu bir fordeyim içinde gizlenemeyecek kadar karmaşık olduğunda veya yalnızca fordöngü içinde erişilebilen değişkenlere güvenir .

for(int i=0;i<array.length&&!((someWidth.X==17 && y < someWidth.x/2) || (y == someWidth.x/2 && someWidth.x == 18);i++)

Birlikte gitmeye karar Yani eğer if- break, kapalı konum. Ancak, forşartlara uymaya karar verirseniz , if- breakve-koşullarının bir karışımını kullanmak zorundasınız for. Tutarlı olmak amacıyla ileri geri koşullarını taşımak zorunda kalacak arasındaki forKOŞUL VE if- breakher koşulları değiştikçe.


4

Dönüşümünüz, döngüye girerken neyin conditiondeğerlendirildiğini varsayar true. Bu durumda bunun doğruluğu hakkında yorum yapamayız, çünkü tanımlanmadı.

Burada "kod satırlarını azaltmak" konusunda başarılı olmak, sonra bakmaya devam edebilirsiniz

for(int i=0;i<array.length;i++){
    // some other code
    if(condition){
        break;
    }
    // further code
}

ve aynı dönüşümü uygulayarak

for(int i=0;i<array.length && !condition;i++){
    // some other code
    // further code
}

Bu, further codedaha önce yapmadığınız bir şeyi koşulsuz olarak yaptığınız gibi geçersiz bir dönüşümdür .

Daha güvenli bir dönüşüm şeması, ayrı bir işleve sahip çıkarıp some other codedeğerlendirme yapmaktır condition.

bool evaluate_condition(int i) // This is an horrible name, but I have no context to improve it
{
     // some other code
     return condition;
}

for(int i=0;i<array.length && !evaluate_condition(i);i++){
    // further code
}

4

TL; DR Özel durumunuzda en iyi ne varsa onu yapın

Bu örneği ele alalım:

for ( int i = 1; i < array.length; i++ ) 
{
    if(something) break;
    // perform operations
}

Bu durumda, for döngüsündeki herhangi bir kodun somethingdoğru olması durumunda çalıştırılmasını istemeyiz , bu nedenle testi somethingkoşul alanına taşımak makul olur.

for ( int i = 1; i < array.length && !something; i++ )

Sonra tekrar, döngünün somethingönüne ayarlanıp ayarlanmamasına bağlı olarak true, ancak bunun içinde olmazsa, daha fazla netlik sunabilir:

if(!something)
{
    for ( int i = 1; i < array.length; i++ )
    {...}
}

Şimdi şunu hayal et:

for ( int i = 1; i < array.length; i++ ) 
{
    // perform operations
    if(something) break;
    // perform more operations
}

Orada çok net bir mesaj gönderiyoruz. somethingDizi işlenirken true olursa , bu noktada tüm işlemi iptal edin. Kontrolü durum alanına taşımak için yapmanız gerekenler:

for ( int i = 1; i < array.length && !something; i++ ) 
{
    // perform operations
    if(!something)
    {
        // perform more operations
    }
}

Muhtemelen, "mesaj" çamurlu hale geldi ve iki durumda arıza durumunu kontrol ediyoruz - ya da başarısızlık durumu değişirse ve bu yerlerden birini unutursak?

Elbette, her birinin kendi nüansları ile bir döngü ve koşul için olabilecek daha birçok farklı şekil vardır.

Kodu iyi okunması için yazın (bu açıkça özneldir) ve net bir şekilde. Bir draconian kodlama kuralları dışında, tüm "kuralların" istisnaları vardır. Neler hissettiğinizi yazdığınızı yazın ve gelecekteki hata olasılığını en aza indirin.


2

Her ne kadar döngü başlığındaki tüm koşulları gördüğünüz ve breakbüyük blokların içinde kafa karıştırıcı olabileceği için çekici olsa da , bir fordöngü çoğu programcının bir aralıkta döngü yapmayı beklediği bir kalıptır.

Özellikle bunu yaptığınızdan, ek bir mola durumu eklemek karışıklığa neden olabilir ve işlevsel olarak eşdeğer olup olmadığını görmek daha zordur .

Genellikle iyi bir alternatif, dizinizin en az bir öğeye sahip olduğunu varsayarak her iki koşulu da kontrol eden bir whileveya do {} whiledöngü kullanmaktır .

int i=0
do {
    // some other code
    i++; 
} while(i < array.length && condition);

Sadece bir koşulu kontrol eden ve döngü başlığından kod çalıştırmayan bir döngü kullanmak, koşul kontrol edildiğinde, gerçek koşulun ve yan etkileri olan kodun ne olduğunu açıkça belirtirsiniz.


Zaten bazı iyi cevaplara sahip olan bu soruya rağmen, bunu özellikle vurgulamak istedim çünkü önemli bir noktaya değindi: benim için, for-loop'da ( for(...; i <= n; ...)) basit bir sınır denetimi dışında herhangi bir şey olması aslında kodun okunmasını zorlaştırıyor çünkü Burada olup bitenleri durdurmak ve düşünmek ve ilk seferde durumu tamamen kaçırabilirler çünkü orada olmasını beklemiyorum. Benim için, bir fordöngü bazı aralıklar üzerinde döngü yaptığınızı, özel bir çıkış koşulu varsa, bir ile açıkça belirtilmesi gerektiğini ifveya bir kullanabilirsiniz while.
CompuChip

1

Bu kod, insanlar tarafından okunması gerektiği için kötüdür - deyimsiz fordöngüler sık ​​sık okumak için kafa karıştırıcıdır, yani böceklerin burada saklanma olasılığı daha yüksektir, ancak orijinal kodun her ikisini de korurken iyileştirilmesi mümkün olabilir kısa ve okunabilir.

İstediğiniz şey bir dizide bir değer bulmaksa (verilen kod örneği biraz geneldir, ancak bu model de olabilir), özel olarak bir programlama dili tarafından özel olarak bu amaç için sağlanan bir işlevi kullanmayı deneyebilirsiniz. Örneğin (sözde kod, bir programlama dili belirtilmediğinden, çözümler belirli bir dile bağlı olarak değişir).

array.find(item -> item.valid)

Bu, kodunuzun özellikle neye ihtiyacınız olduğunu söylediği gibi sadeleştirirken çözümü de kısaltır.


1

Bence birkaç neden olduğunu söylüyor, yapmamalısın.

  1. Bu okunabilirliği azaltır.
  2. Çıkış aynı olmayabilir. Bununla birlikte, bir kod yürütme işleminden sonra durum kontrol edildiğinden bir do...whiledöngü (değil while) ile yapılabilir .

Ama bunun üzerine, bunu düşün,

for(int i=0;i<array.length;i++){

    // Some other code
    if(condition1){
        break;
    }

    // Some more code
    if(condition1){
        break;
    }

    // Some even more code
}

Şimdi, bu koşulları bu duruma ekleyerek gerçekten başarabilir misiniz for?


" Açılış " nedir? " Fikir " mi demek istiyorsun ?
Peter Mortensen

Ne demek "açıklanmaması gerektiğini söyleyen açık sözler" ile ne demek istiyorsun ? Ayrıntılı olabilir misiniz?
Peter Mortensen

0

Bence bu breakkodun kaldırılması iyi bir fikir olabilir ama kod satırlarından tasarruf etmemeliyim.

Onsuz yazmanın avantajı break, döngünün post-koşulunun açık ve net olmasıdır. Döngüyü bitirdiğinizde ve programın bir sonraki satırını çalıştırdığınızda, döngü koşulunuzun i < array.length && !conditionyanlış olması gerekir. Bu nedenle, idizi uzunluğunuzdan büyük veya ona eşit veya conditiondoğruydu.

Sürümünde break, gizli bir gotcha var. Döngü koşulu , her geçerli dizi dizini için başka bir kod çalıştırdığınızda döngünün sona erdiğini , ancak gerçekte breakbundan önce döngüyü sonlandırabilecek bir ifade olduğunu ve döngü kodunu gözden geçirmediğiniz sürece göremeyeceğinizi söyler. çok dikkatli. Ayrıca, derleyicileri optimize etmek de dahil olmak üzere otomatik statik analizörler, döngünün post-koşullarının ne olduğunu belirlemekte zorluk çekebilir.

Edgar Dijkstra'nın “Goto Zararlı Olarak Görülüyor” yazmasının asıl sebebi buydu. Bu bir tarz meselesi değildi: bir döngüyü koparmak programın durumu hakkında resmi olarak mantıklı olmayı zorlaştırıyor. Hayatımda birçok ifade yazdım break;ve bir yetişkin olarak bir tane bile yazdım goto(performans açısından kritik bir iç döngüden birden fazla seviyeden ayrılmak ve daha sonra arama ağacının başka bir dalına devam etmek için). Ancak, returnbir döngüden koşullu bir ifade yazma ihtimalim çok yüksektir (bu döngüden sonra asla kodu çalıştırmaz ve bu nedenle post-koşullarını alamaz) break.

dipnot

Aslında, kodu aynı davranışı vermek için yeniden düzenlemek aslında daha fazla kod satırına ihtiyaç duyabilir. Yeniden düzenlemeniz, başka bir kod için veya bunun conditionyanlış başlatacağını ispatlayabilirsek geçerli olabilir . Ancak, örneğiniz genel durumla aynıdır:

if ( array.length > 0 ) {
  // Some other code.
}
for ( int i = 1; i < array.length && !condition; i++ ) {
  // Some other code.
}

Eğer diğer bazı kod tek liner değil, daha sonra kendini tekrar olmamak için bir işleve taşımak olabilir ve o zaman neredeyse bir kuyruk özyinelemeli fonksiyonu içine döngü refactored ettik.

Bunun, sorunun asıl amacı olmadığını biliyorum, ve sen de basit tutuyordun.


Sorun, ara vermenin kodla ilgili tartışmayı zorlaştırmaması değil, sorun rastgele yerlerde ara vermenin kodu karmaşık hale getirmesidir. Bu gerçekten gerekliyse, mola nedeniyle tartışmak zor değil, ancak kodun karmaşık şeyler yapması gerektiğinden.
gnasher729

İşte bu yüzden aynı fikirde değilim: Eğer bir breakdeyim olmadığını biliyorsanız, döngü koşulunun ne olduğunu ve bu koşul yanlış olduğunda döngünün durduğunu bilirsiniz. Eğer varsa break? Sonra, döngünün sonlanabileceği birden fazla yol vardır ve genel durumda, bunlardan birinin döngünün ne zaman durduracağını anlamak, kelimenin tam anlamıyla Durma Sorunu'nu çözmektedir. Uygulamada, benim daha büyük endişe döngü olduğunu görünüyor bu döngü onun karmaşık mantığı içinde gömülü bir kenar durumda gözardı sonra kod kim yazdıysa aslında tek bir şey yok, ama böyle. Döngü durumda şeyler kaçırmak zor.
Davislor

0

Evet, ancak sözdiziminiz alışılmadık ve dolayısıyla kötü (tm)

Umarım diliniz gibi bir şeyi destekler

while(condition) //condition being a condition which if true you want to continue looping
{
    do thing; //your conditionally executed code goes here
    i++; //you can use a counter if you want to reference array items in order of index
}

2
belki 'durum' için farklı bir kelime kullanmalıydım, örnekte tam olarak aynı koşulu ifade etmeyi kastediyordum
Ewan

1
Sadece for döngüsü değil, sıra dışı bir konvansiyonel bile değildir, bu formun döngüsünün döngü için bir denklemden daha iyi olması için hiçbir neden yoktur. Aslında çoğu insan, CPP Çekirdek Kılavuz İlkelerinin
Sean Burton,

2
Bazı insanlar yaratıcı alternatiflerden nefret eder. Veya bir soruna kafalarınınkinden farklı bir şekilde bakmak. Ya da daha genel olarak, akıllı eşekler. Acının kardeşini hissediyorum!
Martin Maat

1
sean üzgünüm dostum, insanların yanlış olduklarını söylemekten nefret ettiklerini biliyorum, ama sizi es.77'ye yönlendiririm
Ewan

2
Bu while, koddaki canavarı vurgular - aksi halde rutin / sıradan kodda gizlenmiş istisna. İş mantığı ön ve merkezde, döngü mekaniği ele alınmıştır. forDöngü alternatifine "bir dakika bekle ..." reaksiyonundan kaçınır . Bu cevap sorunu düzeltir. kesinlikle oy.
radarbob

0

Aşırı karmaşık bir forifadenin okunması zor olduğundan endişe ediyorsanız , bu kesinlikle geçerli bir husustur. Dikey alanı boşa harcamak da bir konudur (daha az kritik olsa da).

(Şahsen ben bu kuralı sevmediğim ififadeleri hep burada büyük ölçüde boşa dikey boşluk nedeni olan diş telleri olması gerekir. Sorun olduğunu Not israf dikey alan. Kullanma bir sorun olmamalı anlamlı çizgilerle dikey boşluk.)

Bir seçenek, onu birden çok satıra bölmektir. forÇok değişkenli ve koşullu gerçekten karmaşık ifadeler kullanıyorsanız kesinlikle yapmanız gereken budur . (Bu benim için düşey alanı daha iyi kullanmak, mümkün olduğunca anlamlı bir şeyler vermek.)

for (
   int i = 0, j = 0;
   i < array.length && !condition;
   i++, j++
) {
   // stuff
}

Daha bildirici ve daha az zorunlu bir form kullanmaya çalışmak daha iyi bir yaklaşım olabilir. Bu, dile bağlı olarak değişecektir veya bu tür bir şeyi etkinleştirmek için kendi işlevlerinizi yazmanız gerekebilir. Aynı zamanda conditiongerçekte ne olduğuna da bağlıdır . Muhtemelen dizideki içeriğe bağlı olarak bir şekilde değişebilmelidir.

array
.takeWhile(condition)  // condition can be item => bool or (item, index) => bool
.forEach(doSomething); // doSomething can be item => void or (item, index) => void

Karmaşık veya sıradışı bir forifadeyi birden fazla satıra bölmek, bu tartışmadaki en iyi fikirdir
user949300

0

Unutulan bir şey: Bir döngüden koptuğumda (tüm olası yinelemeleri yapma, nasıl yapıldığına bakılmaksızın), genellikle sadece döngüden çıkmak istememekle kalmaz, bunun neden olduğunu bilmek isterim. . Örneğin, bir X öğesini ararsam, yalnızca döngüden koparmakla kalmaz, X'in bulunduğunu ve nerede olduğunu da bilmek isterim.

Bu durumda, döngü dışında bir koşul olması oldukça doğaldır. Bu yüzden başla

bool found = false;
size_t foundIndex;

ve döngüde yazacağım

if (condition) {
    found = true;
    foundIndex = i;
    break;
}

for döngüsü ile

for (i = 0; i < something && ! found; ++i)

Şimdi döngüdeki durumu kontrol etmek oldukça doğal. Bir "break" ifadesinin olup olmadığı, döngüde kaçınmak istediğiniz işlemlerin olup olmamasına bağlıdır. Bazı işlem gerekliyse ve diğer işlem gerekli değilse, gibi bir işleminiz olabilir.

if (! found) { ... }

bir yere döngüde.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.