2011-01-20 14 views
15

Mam sekcję w moim kodzie, gdzie wiem, że potrzebuję tablicy i wiem dokładnie, ile elementów będzie potrzebować ta tablica. Ta sekcja kodu będzie wielokrotnie powtarzana, więc mógłbym uzyskać bardzo duże oszczędności czasu, najpierw inicjując tę ​​tablicę do rozmiaru, który wiem, że będzie potrzebował, a następnie wypełniając go, a tylko naciskając elementy (pchanie byłoby O (n) w przeciwieństwie do wypełniania już utworzonych przestrzeni, które byłyby O (1)).Czy mogę zainicjować tablicę do podanego rozmiaru w Perlu?

Powiedział, że nie mogę znaleźć żadnego eleganckiego sposobu inicjowania tablicy do danego rozmiaru i nie mam pojęcia dlaczego. Wiem, że można zrobić:

my @array; $array[49] =0;

dostać tablicę 50 pozycję, ale to wygląda bardzo brzydko do mnie i czuję się tak, choć nie musi być lepszy sposób. Pomysły?

+2

Nic złego z wcześniejszą alokacją tablic, ale to pachnie jak przedwczesna i mikrooptymalizacja. Dlaczego myślisz, że 'push' to O (n)? – mob

+0

Nie ma czasu na znalezienie linku już teraz, ale długa historia: pchanie wymaga zapętlenia się przez tablicę, aby znaleźć ostatnią otwartą przestrzeń (to jest sposób, w jaki pchanie jest zwykle realizowane, tak czy inaczej, chociaż teraz o tym myślę, to jest dla pojedynczo połączonej listy zamiast zwykle tablicy). Mówisz, że jest inaczej zaimplementowany w Perlu? – Eli

+6

Tak, jest trochę inaczej. Listy Perla są tablicami z pewnym luzem zarówno z przodu, jak iz tyłu. Znają także swój rozmiar, więc zarówno 'push' jak i' unshift' są zwykle O (1). Jeśli luzu zostanie całkowicie zużyty, Perl ponownie przydzieli nową tablicę z większą ilością miejsca. Realokacja jest operacją O (n), ale musi się zdarzyć po każdej operacji push (log) n. – mob

Odpowiedz

13

Szczerze mówiąc, twoja droga jest całkiem niezła, ponieważ wyraźnie zmienia rozmiar tablicy: $#array = 49;;

+12

A jeśli konieczne jest również zainicjowanie elementów, użyj 'my @ array = (0) x50' – slu

3

Twoja droga jest świetna, podobnie jak DVK. Sposób wykonania tego w jednym poleceniu może być następujący:

@array = (0 .. 49);

Ale nie jestem pewien, czy jest bardziej elegancki, ponieważ przypisuje wartość od 1 do 49 dla każdego elementu, ale prawdopodobnie bardziej intuicyjnie jest zrozumieć programistę niezbyt dużo w składni Perla.

+2

-1 Twoja droga jest zła ... Nie przygotowujesz wcześniej, wystarczy ustawić 50 wartości w jednym wierszu! – sebthebert

+3

@sebthebert, właśnie to powiedziałem. Przeczytaj część pod kodem. – cbrandolino

5

Ilekroć myślisz o zrobieniu tego typu optymalizacji, zrób profilowanie! Rezultat może nie być tym, czego oczekujesz. Na przykład, kiedyś następujący krótki skrypt, aby przetestować swoją teorię, że pre-alokacji tablicy jest szybsze:

for (my $loops = 0; $loops < 100000; $loops++) 
{ 
    my @arr; 

    for (my $foo = 0; $foo < 50; $foo++) { 
     push @arr, 'bar'; 
    } 
} 

To trwało 2.13 sekund.

for (my $loops = 0; $loops < 100000; $loops++) 
{ 
    my @arr; 
    $arr[49] = 0; 

    for (my $foo = 0; $foo < 50; $foo++) { 
     $arr[$foo] = 'bar'; 
    } 
} 

Zajęło to 2,16 sekundy (dwa razy wykonałem oba testy). Tak więc kończy się to byciem szybszym, aby po prostu pozwolić perlowowi na przydzielanie tablicy w razie potrzeby.

Aktualizacja

Po wprowadzeniu zmian sugerowanych przez ysth, numery zrobić trochę więcej sensu: 2.27 sekund metodą „push” oraz 2.21 do wstępnego przydziału. Mimo to, chciałbym zapytać, czy taka optymalizacja naprawdę zaoszczędziłaby kiedykolwiek (różnica wynosiła zaledwie 0,06 sekundy po 100 000 iteracji).

+0

Interesujące! Dzięki! Z wyjątkiem tego, że nie rozumiem, jak to jest możliwe ... – Eli

+0

@arr jest ponownie wykorzystywany z jednej iteracji do następnej; aby zmusić go do nieużywania ponownie, powiedz 'my $ arrref;' przed zewnętrzną pętlą i '$ arrref = \ @ arr;' na końcu zewnętrznej pętli. – ysth

+0

Zaktualizowałem moją odpowiedź, aby odzwierciedlić sugestię ystha. Przypuszczam, że jest to dobry sposób na uzyskanie bardziej obiektywnego wyniku, ale czy coś takiego można zrobić w realnym świecie? – Brian

11
  1. Pierwsza zasada Klubu Optymalizacji polega na tym, że nie Optymalizujesz.
  2. Druga zasada Klubu Optymalizacji to: Nie Optymalizuj bez pomiaru.

Mierz, mierz, mierz przed pójściem i zakładaj, że możesz to zrobić szybciej przez oszukanie Perla. Perl optymalizował często użytkowanie o wiele dłużej niż Ty. Zaufaj temu.

2

Zamiast konkretnego zastosowania wartości UNDEF

my @array; 
$array[49] = undef; 
1

Preallocating może nie pomóc dużo z prędkością, ale może pomóc w powrocie pamięć do systemu, jeśli kawałki przeznaczone są na tyle duże

Powiązane problemy