Znalazłem następującą adnotację w pętli w dużym projekcie, nad którym pracuję (pseudokod):
var someOtherArray = [];
for (var i = 0, n = array.length; i < n; i++) {
someOtherArray[i] = modifyObjetFromArray(array[i]);
}
To, co zwróciło moją uwagę, to ta dodatkowa zmienna „n”. Nigdy wcześniej nie widziałem napisanego w ten sposób for for lop.
Oczywiście w tym scenariuszu nie ma powodu, dla którego ten kod nie mógłby zostać napisany w następujący sposób (do czego jestem bardzo przyzwyczajony):
var someOtherArray = [];
for (var i = 0; i < array.length; i++) {
someOtherArray[i] = modifyObjetFromArray(array[i]);
}
Ale przyszło mi do głowy.
Czy istnieje scenariusz, w którym napisanie takiej pętli for miałoby sens? Przychodzi mi na myśl, że długość „tablicy” może się zmieniać podczas wykonywania pętli for, ale nie chcemy zapętlać dalej niż pierwotny rozmiar, ale nie wyobrażam sobie takiego scenariusza.
Zmniejszenie tablicy wewnątrz pętli również nie ma większego sensu, ponieważ prawdopodobnie otrzymamy OutOfBoundsException.
Czy istnieje znany wzorzec projektowy, w którym ta adnotacja jest przydatna?
Edytuj Jak zauważył @ Jerry101 przyczyną jest wydajność. Oto link do testu wydajności, który utworzyłem: http://jsperf.com/ninforloop . Moim zdaniem różnica nie jest wystarczająco duża, chyba że iterujesz przez bardzo dużą tablicę. Kod, z którego go skopiowałem, miał tylko do 20 elementów, więc myślę, że czytelność w tym przypadku przeważa nad wydajnością.
źródło
n
może być wolniejsze niż użycie wariantu,array.Length
ponieważ JITter może nie zauważyć, że może wyeliminować sprawdzanie granic tablicy.Odpowiedzi:
Zmienna
n
zapewnia, że wygenerowany kod nie pobiera długości tablicy dla każdej iteracji.Jest to optymalizacja, która może mieć wpływ na czas działania w zależności od używanego języka, niezależnie od tego, czy tablica jest w rzeczywistości obiektem kolekcji, czy „tablicą” JavaScript, i innymi szczegółami optymalizacji.
źródło
n
obejmuje pętlę, co zwykle jest dobrą rzeczą. Zdefiniowałbym to przed pętlą, tylko gdybym chciał go później użyć ponownie.Pobieranie długości tablicy może być z łatwością „droższe” niż faktyczna akcja, nad którą iterujesz.
Więc jeśli zestaw się nie zmienia, zapytaj o długość tylko raz.
Nie z tablicami, ale z zestawami rekordów pochodzącymi z serwera sql. Widziałem radykalną poprawę, nie sprawdzając liczby rekordów przy każdej iteracji. (oczywiście rób to tylko wtedy, gdy możesz zagwarantować, że tablica lub zestaw rekordów nie ulegną zmianie podczas tego procesu).
źródło
Ludzie rozmawiający o wydajności prawdopodobnie mają rację, dlatego właśnie tak zostało napisane (osoba, która to napisała w ten sposób, może nie mieć racji, że znacząco wpływa na wydajność, ale to inna sprawa).
Jednak, aby odpowiedzieć na tę część pytania, myślę, że najprawdopodobniej stanie się to, gdy głównym celem pętli jest modyfikacja tablicy, w której zapętla się ona. Rozważ coś takiego w pseudokodzie:
Oczywiście są inne sposoby na napisanie tego. W tym przypadku mogłem sprawdzić, czy są plusy w tym samym czasie, co sprawdzenie, czy adresaci zaakceptowali zaproszenia i utworzyli pełną listę gości po jednym zaproszeniu. Niekoniecznie chcę połączyć te dwie operacje, ale nie mogę od razu wymyślić powodu, dla którego jest to zdecydowanie błędne, i dlatego ten projekt jest wymagany . Czasami jest to opcja do rozważenia.
Właściwie myślę, że najbardziej błędne w tym kodzie jest to, że członkostwo w
guests
tablicy oznacza różne rzeczy w różnych punktach kodu. Dlatego z pewnością nie nazwałbym tego „wzorem”, ale nie wiem, czy to wystarczająca wada, aby wykluczyć robienie czegoś takiego :-)źródło
Jeśli to w ogóle możliwe, powinieneś użyć iteratora, który przemierza wszystkie elementy tablicy. Używasz tablicy jako sekwencji, a nie jako pamięci o dostępie swobodnym, więc byłoby oczywiste, że iterator, który po prostu wykonuje dostęp sekwencyjny, byłby szybszy. Wyobraź sobie, że tablica jest w rzeczywistości drzewem binarnym, ale ktoś napisał kod, który określa „długość” poprzez zliczenie elementów i kod, który uzyskuje dostęp do i-tego elementu, również przez przemierzanie elementu, każdy w O (n ). Iterator może być bardzo szybki, twoja pętla będzie wolna.
źródło