Bu ekstra değişkeni for döngüsü ek açıklamasında kullanmanın herhangi bir faydası var mı?


11

Üzerinde çalıştığım büyük bir projede (pseudocode) aşağıdaki döngü notunu buldum:

var someOtherArray = [];
for (var i = 0, n = array.length; i < n; i++) {
    someOtherArray[i] = modifyObjetFromArray(array[i]);
}

Dikkatimi çeken bu ekstra "n" değişken. Daha önce hiç bu şekilde yazılmış bir lop görmedim.

Açıkçası bu senaryoda bu kodun aşağıdaki şekilde yazılamamasının bir nedeni yoktur (ki bu çok alışkınım):

var someOtherArray = [];
for (var i = 0; i < array.length; i++) {
    someOtherArray[i] = modifyObjetFromArray(array[i]);
}

Ama beni düşündürdü.

Böyle bir for döngüsü yazarken mantıklı bir senaryo var mı? Fikir akla geliyor "dizi" uzunluğu for döngüsü yürütme sırasında değişebilir, ama biz orijinal boyuttan daha fazla döngü istemiyorum, ama böyle bir senaryo hayal edemiyorum.

Dizinin döngü içinde küçültülmesi de pek mantıklı değil, çünkü OutOfBoundsException'ı büyük olasılıkla alacağız.

Bu ek açıklamanın yararlı olduğu bilinen bir tasarım deseni var mı?

Düzenle @ Jerry101 tarafından belirtildiği gibi performans nedeni. İşte oluşturduğum performans testine bir link: http://jsperf.com/ninforloop . Bence çok büyük bir dizi olsa yineleme sürece fark yeterince büyük değil. Ben kopyaladım kodu sadece 20 kadar eleman vardı, bu yüzden bu durumda okunabilirlik performans dikkate ağır basar düşünüyorum.


Düzenlemenize tepki olarak: bu nesne yönelimli programlamadır. Standart array.length hızlı ve ucuzdur. Ancak, herhangi bir nedenle, .length'in uygulanması pahalı bir şeye dönüşebilir. Bir değer aynı kalırsa, değeri birden fazla almayın.
Pieter B

Katılıyorum. Bu seçeneği bilmek güzel, ancak sql sorgunuza benzer bir örnek almadıkça muhtemelen çok sık kullanmazdım. You☺ ederiz
Vlad spreyler

Yani, diziniz bir milyon öğe ise, değer aynı kalırken array.length değerini 1 kez yerine milyon kez çağırırsınız. Milyonlarca kez bir şey sormak ve her bir sonraki cevabın ilk cevapla aynı olacağını bilmek ...... bana biraz saçma geliyor.
Pieter B

1
Bu kodu okumak önemli ölçüde zorlaştırıyor bulmuyorum. (Cidden, eğer birisi böyle basit bir döngü ile sorun yaşarsa, endişelenmelidirler.) Ama: 1) 4 yıl süren C ve C-inişli dillerden sonra, her ciddi derleyici zaten bunu yapmadıysa çok şaşırırdım senin için; ve 2) bu bir etkin nokta olmayabilir. Birinin bir kitaplığın içinde olmadığı sürece ayrıştırmak için fazladan 5 saniye daha harcamasına değer görünmüyor (örn. Veri yapısının uygulanması.)
Doval

1
C # /. NET'te, JITter dizi sınırlama kontrollerini ortadan kaldırabileceğini fark etmeyebileceğinden n, varyant kullanımı varyanttan daha yavaş array.Lengtholabilir.
CodesInChaos

Yanıtlar:


27

Değişken n, oluşturulan kodun her yineleme için dizi uzunluğunu getirmemesini sağlar.

Kullanılan dile, dizinin bir toplama nesnesi mi yoksa bir JavaScript "dizisi" mi olduğuna ve diğer optimizasyon ayrıntılarına bağlı olarak, çalışma süresinde fark yaratabilecek bir optimizasyon.


3
Hayır. Dizinin uzunluğunun her yinelemenin getirilip getirilmediği yalnızca dile değil, aynı zamanda derleyici ve derleyici seçeneklerine ve döngüde ne yapıldığına da bağlıdır (C ve C ++ hakkında konuşuyorum)
BЈовић

.. Ve buna rağmen, ben gerçekten isteseydim, şahsen n atamasını döngünün hemen üstüne koyardım, çünkü OP'nin belirttiği gibi, bu nadir kullanılan (YMMV) bir yapıdır ve diğer geliştiriciler tarafından kolayca kaçırılır / anlaşılmaz kod.
cwap

20
Yazıldığı gibi n, genellikle iyi bir şey olan döngüyü kapsamaktadır. Döngüden önce, ancak daha sonra tekrar kullanmak istersem tanımlarım.
Jerry101

4
@ Jerry101: Görünüşe göre örnek snippet, bir döngü kapsamı diye bir şeyin olmadığı JavaScript'tir ...
Bergi

1
@ BЈовић: pratikte, derleyici nadiren dizi boyutunun değişmediğini kanıtlamayı başarır (tipik olarak sadece üzerinde döngü yaptığınız vektör fonksiyon için yerel ise ve döngüde sadece inline fonksiyonları çağırıyorsanız) önemsiz bir şekilde kanıtlanabilir.
Matteo Italia

2

Dizinin uzunluğunun getirilmesi, yinelediğiniz gerçek işlemden sonra "daha pahalı" olabilir.

Bu yüzden küme değişmezse, uzunluğu yalnızca bir kez sorgulayın.

Dizilerle değil, bir sql sunucusundan gelen kayıt kümeleriyle, her yinelemede kayıt sayısını sorgulamadan çarpıcı iyileştirmeler gördüm. (elbette bunu sadece dizi veya kayıt kümesinin bu işlem sırasında değişmemesini garanti ederseniz yapın).


Kayıt sayısı değişirse, ne olacak? 100 öğe olduğunu ve 50. öğeyi işlerken # 25 öğesinden sonra bir öğe eklendiğini varsayalım. 51. maddeyi işlediğinizde, önceden işlemiş olduğunuz # 50 ile aynıdır ve işler ters gider. Sorun şu ki, uzunluk değişmiyor, çok daha yaygın.
gnasher729

@ gnasher729 Asimetrik davranışa girdikten sonra yanlış gidebilecek çok şey var. Ama buna karşı başlayabileceğiniz ve sql işlemi gibi şeyler yapabilirsiniz.
Pieter B

2

Fikir akla geliyor "dizi" uzunluğu for döngüsü yürütme sırasında değişebilir, ama biz orijinal boyuttan daha fazla döngü istemiyorum, ama böyle bir senaryo hayal edemiyorum.

Performans hakkında konuşan insanlar muhtemelen bu yüzden yazılmıştır (bu şekilde yazan kişi performansı önemli ölçüde etkilediği doğru olmayabilir, ancak bu başka bir konudur).

Ancak, sorunuzun bu kısmını yanıtlamak için, döngünün ana amacı üzerinde döngü oluşturduğu diziyi değiştirmek olduğunda gerçekleşme olasılığının yüksek olduğunu düşünüyorum. Sözde kodda böyle bir şey düşünün:

guests = [];
for (i = 0; i < invitations.length; ++i) {
    if (! invitations[i].is_declined()) {
        guests.append(invitations[i].recipient())
    }
}
// maybe some other stuff to modify the guestlist
for (i = 0, n = guests.length; i < n; ++i) {
    if (guests[i].has_plus_one()) {
        guests.append(guests[i].get_plus_one());
    }
}

Elbette yazmanın başka yolları da var. Bu durumda, alıcıların davetiyelerini kabul edip etmediğini kontrol ederek artı olanları da kontrol edebilir ve her seferinde bir davetli listesi oluşturabilirdim. Bu iki işlemi birleştirmek istemiyorum, ancak bunun kesinlikle yanlış olmasının bir sebebini hemen düşünemiyorum ve bu nedenle bu tasarım gerekli . Zaman zaman dikkate almak için bir seçenek.

Aslında bu kod ile en yanlış şey guestsdizi üyeliği kod farklı noktalarda farklı şeyler anlamına olduğunu düşünüyorum . Bu yüzden kesinlikle buna "desen" demezdim, ama bu tür bir şey yapmayı dışlamak için yeterli bir kusur olduğunu bilmiyorum :-)


Dizi başka bir iş parçacığı tarafından da değiştirilebilir. Bu, derleyicinin uzunluk erişimini optimize etmesini önler. Dolayısıyla, söz konusu programcı açık bir şekilde dizinin diğer iş parçacıklarında bile değişmediğini söylüyor.
Basilevs

0

Mümkünse, dizinin tüm öğelerini çaprazlayan bir yineleyici kullanmalısınız. Diziyi rasgele erişimli depolama olarak değil, bir sıra olarak kullanırsınız, bu nedenle yalnızca sıralı erişim yapan bir yineleyicinin daha hızlı olacağı açıktır. Bir dizinin aslında ikili bir ağaç olduğunu düşündüğünüzü düşünün, ancak birileri öğeleri sayarak "uzunluğu" belirleyen bir kod yazdı ve her biri O (n ). Bir yineleyici çok hızlı olabilir, döngünüz sloooooow olacaktır.

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.