Repeat String-Javascript

Jaka jest najlepsza lub najbardziej zwięzła metoda zwracania ciągu powtarzanego dowolną ilość razy?

Oto mój najlepszy strzał do tej pory:

function repeat(s, n){
    var a = [];
    while(a.length < n){
        a.push(s);
    }
    return a.join('');
}
Author: brad, 2008-10-15

28 answers

Uwaga dla nowych czytelników: Ta odpowiedź jest stara i niezbyt praktyczna - jest po prostu "mądra", ponieważ używa rzeczy tablicy, aby uzyskać Ciągnąć rzeczy zrobione. Kiedy pisałem "mniej procesu" miałem na myśli "mniej kodu", ponieważ, jak zauważyli inni w kolejnych odpowiedziach, to występuje jak świnia. Więc nie używaj go, jeśli prędkość ma dla Ciebie znaczenie.

Umieściłbym tę funkcję bezpośrednio na obiekcie String. Zamiast tworzyć tablicę, wypełniać ją i łączyć z pustą char, po prostu utwórz tablicę o odpowiedniej długości i połącz ją z żądanym ciągiem znaków. Ten sam wynik, mniej procesu!

String.prototype.repeat = function( num )
{
    return new Array( num + 1 ).join( this );
}

alert( "string to repeat\n".repeat( 4 ) );
 394
Author: Peter Bailey,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-06-07 17:24:33

Przetestowałem skuteczność wszystkich proponowanych podejść.

Oto najszybszy wariant jaki mam.

String.prototype.repeat = function(count) {
    if (count < 1) return '';
    var result = '', pattern = this.valueOf();
    while (count > 1) {
        if (count & 1) result += pattern;
        count >>= 1, pattern += pattern;
    }
    return result + pattern;
};

Lub jako samodzielna funkcja:

function repeat(pattern, count) {
    if (count < 1) return '';
    var result = '';
    while (count > 1) {
        if (count & 1) result += pattern;
        count >>= 1, pattern += pattern;
    }
    return result + pattern;
}

Opiera się na algorytmie artistoex . Jest naprawdę szybki. Im większy count, tym szybciej idzie w porównaniu z tradycyjnym podejściem new Array(count + 1).join(string).

Zmieniłem tylko 2 rzeczy:

  1. zastąpione pattern = this przez pattern = this.valueOf() (usuwa jeden oczywisty Typ konwersja);
  2. Dodano if (count < 1) sprawdzanie z prototypejs na górze funkcji, aby wykluczyć niepotrzebne akcje w takim przypadku.
  3. zastosowana optymalizacja z Dennis odpowiedź (5-7% szybciej)

UPD

Stworzyliśmy mały plac zabaw do testowania wydajności tutaj dla zainteresowanych.

zmienna count ~ 0 .. 100:
testowanie wydajności różnych wariantów strun.powtórz() http://tinyurl.com/kb3raxr

stała count = 1024:
testowanie wydajności różnych wariantów strun.repeat() http://tinyurl.com/k527auo

Użyj go i zrób to jeszcze szybciej, jeśli możesz:)

 197
Author: disfated,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 11:33:24

Ten problem jest dobrze znanym / "klasycznym" problemem optymalizacji dla JavaScript, spowodowanym faktem, że łańcuchy JavaScript są "niezmienne"i dodanie przez połączenie nawet jednego znaku do łańcucha wymaga utworzenia, w tym alokacji pamięci dla i kopiowania do, całego nowego łańcucha.

Niestety, zaakceptowana odpowiedź na tej stronie jest błędna, gdzie "zła" oznacza współczynnik wydajności 3x dla prostych ciągów jednoznakowych, a 8X-97x dla krótkich ciągów powtarzanych więcej razy, do 300x za powtarzanie zdań, i nieskończenie źle, gdy przyjmuje granicę współczynników złożoności algorytmów jako n idzie do nieskończoności. Na tej stronie znajduje się również inna odpowiedź, która jest prawie słuszna (oparta na jednej z wielu generacji i odmian poprawnego rozwiązania krążących w Internecie w ciągu ostatnich 13 lat). Jednak to "prawie właściwe" rozwiązanie pomija kluczowy punkt poprawnego algorytmu, powodując 50% wydajność degradacja.

JS Performance Results for the accepted answer, the top-performing other answer (based on a degraded version of the original algorithm in this answer), and this answer using my algorithm created 13 years ago

~ paĺşdziernik 2000 opublikowaĺ 'em algorytm dla tego dokĹ' adnego problemu, ktĂłry zostaĹ 'szeroko zaadaptowany, zmodyfikowany, a nastÄ ™ pnie w koĹ" cu słabo zrozumiany i zapomniany. Aby temu zaradzić, w sierpniu 2008 roku opublikowałem artykuł http://www.webreference.com/programming/javascript/jkm3/3.html Wyjaśnienie algorytmu i wykorzystanie go jako przykład prostych optymalizacji JavaScript ogólnego przeznaczenia. Do tej pory Web Reference wyczyścił moje dane kontaktowe, a nawet moje imię i nazwisko z tego artykułu. I po raz kolejny algorytm został szeroko zaadaptowany, zmodyfikowany, a następnie słabo zrozumiany i w dużej mierze zapomniany.

Oryginalny algorytm powtarzania/mnożenia łańcuchów przez Józef Myers, circa Y2K jako funkcja mnożenia tekstu w tekście.js; opublikowano sierpień, 2008 w Kategorii Web Reference: http://www.webreference.com/programming/javascript/jkm3/3.html (The artykuł wykorzystał funkcję jako przykład optymalizacji JavaScript, która jest jedyną dziwną nazwą " stringFill3.")

/*
 * Usage: stringFill3("abc", 2) == "abcabc"
 */

function stringFill3(x, n) {
    var s = '';
    for (;;) {
        if (n & 1) s += x;
        n >>= 1;
        if (n) x += x;
        else break;
    }
    return s;
}

W ciągu dwóch miesięcy od publikacji tego artykułu, to samo pytanie zostało wysłane do Stack Overflow i poleciało pod moim radarem aż do teraz, kiedy najwyraźniej oryginalny algorytm tego problemu został po raz kolejny zapomniany. Najlepszym rozwiązaniem dostępnym na tej stronie przepełnienia stosu jest zmodyfikowana wersja mojego rozwiązania, ewentualnie oddzielona kilkoma generacjami. Niestety modyfikacje zrujnowały optymalność rozwiązania. W rzeczywistości, zmieniając strukturę pętli z oryginału, zmodyfikowane rozwiązanie wykonuje zupełnie niepotrzebny dodatkowy krok wykładniczego powielania (łącząc w ten sposób największy ciąg używany we właściwym odpowiedź z siebie dodatkowy czas, a następnie odrzucenie go).

Poniżej następuje omówienie niektórych optymalizacji JavaScript związanych ze wszystkimi odpowiedziami na ten problem i z korzyścią dla wszystkich.

Technika: unikaj odniesień do obiektów lub właściwości obiektów

Aby zilustrować, jak działa ta technika, używamy funkcji JavaScript, która tworzy ciągi o dowolnej długości. Jak zobaczymy, można dodać więcej optymalizacji!

Funkcja podobnie jak ten używany tutaj jest do tworzenia wypełnień wyrównujących kolumny tekstu, do formatowania pieniędzy lub do wypełniania danych bloków aż do granicy. Funkcja generowania tekstu umożliwia również wprowadzanie zmiennej długości do testowania innych funkcji działających na tekście. Ta funkcja jest jednym z ważnych elementów modułu przetwarzania tekstu JavaScript.

Kontynuując, omówimy jeszcze dwie najważniejsze techniki optymalizacji podczas opracowywania oryginalnego kodu do zoptymalizowany algorytm tworzenia ciągów. Efektem końcowym jest wytrzymała, wysokowydajna funkcja, której używałem wszędzie-wyrównywanie cen artykułów i sumy w formularzach zamówień JavaScript, formatowanie danych i formatowanie wiadomości e-mail / tekstowych i wiele innych zastosowań.

Oryginalny kod do tworzenia ciągów stringFill1()

function stringFill1(x, n) { 
    var s = ''; 
    while (s.length < n) s += x; 
    return s; 
} 
/* Example of output: stringFill1('x', 3) == 'xxx' */ 

Składnia jest tutaj jasna. Jak widać, użyliśmy już lokalnych zmiennych funkcji, zanim przejdziemy do więcej optymalizacje.

Należy pamiętać, że istnieje jedno niewinne odniesienie do Właściwości obiektu s.length w kodzie, które szkodzi jego wydajności. Co gorsza, zastosowanie tej właściwości obiektu zmniejsza prostotę programu poprzez założenie, że czytelnik wie o właściwościach JavaScript string objects.

Użycie tej właściwości obiektu niszczy ogólność programu komputerowego. Program zakłada, że x musi być ciągiem o długości 1. Ogranicza to zastosowanie funkcji stringFill1() do czegokolwiek z wyjątkiem powtarzania pojedynczych znaków. Nawet pojedyncze znaki nie mogą być używane, jeśli zawierają wiele bajtów, takich jak encja HTML &nbsp;.

Najgorszy problem spowodowany niepotrzebnym użyciem właściwości obiektu polega na tym, że funkcja tworzy nieskończoną pętlę, jeśli jest testowana na pustym łańcuchu wejściowym x. Aby sprawdzić ogólność, zastosuj program do najmniejszej możliwej ilości danych wejściowych. Program, który zawiesza się, gdy zostanie poproszony o przekroczenie kwoty dostępna pamięć ma wymówkę. Program taki jak ten, który zawiesza się, gdy poproszony o wyprodukowanie niczego nie jest niedopuszczalny. Czasami ładny kod to trujący kod.

Prostota może być dwuznacznym celem programowania komputerowego, ale generalnie tak nie jest. Gdy programowi brakuje jakiegokolwiek rozsądnego poziomu ogólności, nie jest słuszne powiedzenie: "program jest wystarczająco dobry, o ile idzie."Jak widać, użycie właściwości string.length uniemożliwia działanie tego programu w ogólnych ustawieniach, a w rzeczywistości, nieprawidłowy program może spowodować awarię przeglądarki lub systemu.

Czy istnieje sposób, aby poprawić wydajność tego JavaScript, a także zająć się tymi dwoma poważnymi problemami?

Oczywiście. Użyj liczb całkowitych.

Zoptymalizowany kod do tworzenia ciągów stringFill2()

function stringFill2(x, n) { 
    var s = ''; 
    while (n-- > 0) s += x; 
    return s; 
} 

Kod czasu do porównania stringFill1() i stringFill2()

function testFill(functionToBeTested, outputSize) { 
    var i = 0, t0 = new Date(); 
    do { 
        functionToBeTested('x', outputSize); 
        t = new Date() - t0; 
        i++; 
    } while (t < 2000); 
    return t/i/1000; 
} 
seconds1 = testFill(stringFill1, 100); 
seconds2 = testFill(stringFill2, 100); 

Dotychczasowy sukces stringFill2()

stringFill1() zajmuje 47.297 mikrosekund (milionowych części drugi) Wypełnienie 100-bajtowego ciągu, a stringFill2() zajmuje 27,68 mikrosekund, aby zrobić to samo. To prawie podwojenie wydajności poprzez unikanie odniesienia do Właściwości obiektu.

Technika: unikaj dodawania krótkich strun do długich strun

Nasz poprzedni wynik wyglądał dobrze -- bardzo dobrze, w rzeczywistości. Ulepszona funkcja stringFill2() jest znacznie szybsza dzięki zastosowaniu dwóch pierwszych optymalizacji. Uwierzyłbyś, gdybym ci powiedział, że można go ulepszyć, aby był wielokrotnie szybszy niż jest teraz?

Tak, możemy osiągnąć ten cel. Teraz musimy wyjaśnić, w jaki sposób unikamy dodawania krótkich strun do długich strun. Krótkoterminowe zachowanie wydaje się być całkiem dobre w porównaniu z naszą pierwotną funkcją. Informatycy lubią analizować "asymptotyczne zachowanie" funkcji lub algorytmu programu komputerowego, co oznacza badanie jego długoterminowego zachowania poprzez testowanie go z większymi wejściami. Czasami bez wykonywania dalszych badań, nigdy nie staje się świadomy sposobów, które można by poprawić program komputerowy. Aby zobaczyć, co się stanie, stworzymy 200-bajtowy ciąg znaków.

Problem, który pojawia się z stringFill2()

Używając naszej funkcji timing, stwierdzamy, że czas wzrasta do 62,54 mikrosekund dla 200-bajtowego ciągu, w porównaniu do 27,68 dla 100-bajtowego ciągu. Wydaje się, że czas powinien być podwojony Na wykonanie dwukrotnie więcej pracy, ale zamiast tego jest potrojony lub czterokrotnie. Z doświadczenia programistycznego wynik ten wydaje się dziwny, ponieważ jeśli już, funkcja powinna być nieco szybsza, ponieważ praca jest wykonywana bardziej efektywnie (200 bajtów na wywołanie funkcji, a nie 100 bajtów na wywołanie funkcji). Ten problem ma związek z podstępną właściwością JavaScript strings: JavaScript strings are " immutable."

Immutable oznacza, że nie można zmienić ciągu znaków po jego utworzeniu. Dodając po jednym bajcie na raz, nie wykorzystujemy jeszcze jednego bajtu wysiłku. Odtwarzamy cały ciąg plus jeszcze jeden bajt.

W efekcie, aby dodać jeszcze jeden bajt do 100-bajtowego ciągu, potrzeba 101 bajtów pracy. Przeanalizujmy krótko koszt obliczeniowy utworzenia ciągu N bajtów. Koszt dodania pierwszego bajtu wynosi 1 jednostkę wysiłku obliczeniowego. Koszt dodania drugiego bajtu to nie jedna jednostka, ale 2 jednostki (skopiowanie pierwszego bajtu do nowego obiektu string oraz dodanie drugiego bajtu). Trzeci bajt wymaga kosztu 3 jednostek, itp.

C(N) = 1 + 2 + 3 + ... + N = N(N+1)/2 = O(N^2). Symbolem O(N^2) jest wymawiane Duże O Z N do kwadratu, a to oznacza, że koszt obliczeniowy w dłuższej perspektywie jest proporcjonalny do kwadratu długości ciągu. Stworzenie 100 znaków zajmuje 10 000 jednostek pracy, a stworzenie 200 znaków zajmuje 40 000 jednostek pracy.

Dlatego stworzenie 200 znaków zajęło ponad dwa razy więcej czasu niż 100 znaków. W rzeczywistości powinno to zająć cztery razy więcej czasu. Nasze doświadczenie w programowaniu było poprawne, ponieważ praca jest wykonywana nieco bardziej efektywnie dla dłuższych strun, a więc trwało to tylko około trzy razy dłużej. Gdy narzut wywołania funkcji staje się nieistotny, jak długo tworzymy ciąg znaków, w rzeczywistości utworzenie ciągu dwa razy dłuższego zajmie cztery razy więcej czasu.

(Uwaga historyczna: ta analiza nie musi mieć zastosowania do łańcuchów w kodzie źródłowym, takich jak html = 'abcd\n' + 'efgh\n' + ... + 'xyz.\n', ponieważ kompilator kodu źródłowego JavaScript może połączyć te łańcuchy razem przed przekształceniem ich w obiekt JavaScript string. Just a kilka lat temu implementacja KJS JavaScript zawiesiła się lub zawiesiła podczas ładowania długich ciągów kodu źródłowego połączonych znakami plus. Ponieważ czas obliczeniowy był O(N^2), nie było trudno stworzyć strony internetowe, które przeciążały przeglądarkę Konqueror lub Safari, które używały rdzenia silnika JavaScript KJS. Po raz pierwszy natknąłem się na ten problem, gdy opracowywałem język znaczników i parser języka znaczników JavaScript, a następnie odkryłem, co było przyczyną problemu, gdy pisałem mój skrypt dla Javascript Includes.)

Oczywiście ta szybka degradacja wydajności jest ogromnym problemem. Jak możemy sobie z tym poradzić, biorąc pod uwagę, że nie możemy zmienić sposobu obsługi łańcuchów JavaScript jako obiektów niezmiennych? Rozwiązaniem jest użycie algorytmu, który odtwarza ciąg tak kilka razy, jak to możliwe.

Aby wyjaśnić, naszym celem jest uniknięcie dodawania krótkich ciągów do długich ciągów, ponieważ aby dodać krótki ciąg, cały długi ciąg również musi być duplikowany.

Jak algorytm działa, aby uniknąć dodawania krótkich ciągów do długich ciągów

Oto dobry sposób na zmniejszenie liczby nowych obiektów string. Połącz ze sobą dłuższe ciągi znaków, tak aby do wyjścia dodawano więcej niż jeden bajt na raz.

Na przykład, aby ciąg o długości N = 9:

x = 'x'; 
s = ''; 
s += x; /* Now s = 'x' */ 
x += x; /* Now x = 'xx' */ 
x += x; /* Now x = 'xxxx' */ 
x += x; /* Now x = 'xxxxxxxx' */ 
s += x; /* Now s = 'xxxxxxxxx' as desired */

Wykonanie tego zadania wymagało utworzenia ciągu o długości 1, utworzenia ciągu o długości 2, utworzenia ciągu o długości 4, utworzenia ciągu o długości 8 i wreszcie, tworząc ciąg o długości 9. Ile kosztów zaoszczędziliśmy?

Stary Koszt C(9) = 1 + 2 + 3 + 4 + 5 + 6 + 7 + 9 = 45.

Nowy koszt C(9) = 1 + 2 + 4 + 8 + 9 = 24.

Zauważ, że musieliśmy dodać ciąg o długości 1 do Ciągu o długości 0, następnie ciąg o długości 1 do Ciągu o długości 1, następnie ciąg o długości 2 do Ciągu o długości 2, następnie ciąg o długości 4 do Ciągu o długości 4, następnie ciąg o długości 8 do Ciągu o długości 1, Aby uzyskać ciąg o długości 9. To, co robimy, można podsumować jako unikanie dodawania krótkich ciągów do długich ciągów lub innymi słowy, próba połączenia ciągów ze sobą, które są równe lub prawie równej długości.

Dla starego kosztu obliczeniowego znaleźliśmy wzór N(N+1)/2. Czy istnieje formuła nowego kosztu? Tak, ale to skomplikowane. Ważne jest to, że jest to O(N), a więc podwojenie długości sznurka w przybliżeniu podwoi ilość pracy, a nie poczwórnie ją.

Kod, który implementuje tę nową ideę, jest prawie jak skomplikowany jako wzór na koszt obliczeniowy. Kiedy to przeczytasz, pamiętaj, że >>= 1 oznacza przesunięcie w prawo o 1 bajt. Jeśli więc n = 10011 jest liczbą binarną, to n >>= 1 daje wartość n = 1001.

Druga część kodu, której możesz nie rozpoznać, to operator bitowy i, napisany &. Wyrażenie n & 1 oblicza wartość true, jeśli ostatnia cyfra binarna n wynosi 1, a wartość false, jeśli ostatnia cyfra binarna n wynosi 0.

Nowy bardzo wydajny stringFill3() function

function stringFill3(x, n) { 
    var s = ''; 
    for (;;) { 
        if (n & 1) s += x; 
        n >>= 1; 
        if (n) x += x; 
        else break; 
    } 
    return s; 
} 

Wygląda brzydko dla niewprawnego oka, ale jego wykonanie jest niczym innym jak piękne.

Zobaczmy, jak dobrze ta funkcja działa. Po obejrzeniu wyników prawdopodobnie nigdy nie zapomnisz różnicy między algorytmem O(N^2) a algorytmem O(N).

stringFill1() Tworzenie 200-bajtowego ciągu zajmuje 88,7 mikrosekund (milionowych części sekundy), stringFill2() zajmuje 62,54, a stringFill3() zajmuje tylko 4,608. Co sprawiło, że algorytm ten tak bardzo lepiej? Wszystkie funkcje korzystały z lokalnych zmiennych funkcyjnych, ale korzystając z drugiej i trzeciej techniki optymalizacji dodano dwudziestokrotną poprawę wydajności stringFill3().

Głębsza analiza

Co sprawia, że ta konkretna funkcja wywala konkurencję z wody?

Jak już wspomniałem, powodem, dla którego obie te funkcje, stringFill1() i stringFill2(), działają tak wolno, jest to, że ciągi JavaScript są niezmienne. Pamięć nie może być realokowany, aby umożliwić dołączanie kolejnych bajtów na raz do danych łańcuchowych przechowywanych przez JavaScript. Za każdym razem, gdy na końcu łańcucha jest dodawany jeszcze jeden bajt, cały łańcuch jest regenerowany od początku do końca.

Tak więc, aby poprawić wydajność skryptu, należy wstępnie obliczyć dłuższe ciągi, łącząc dwa ciągi ze sobą z wyprzedzeniem, a następnie rekurencyjnie budować żądaną długość.

Na przykład, aby utworzyć 16-literowy łańcuch bajtowy, najpierw zostanie wstępnie obliczony łańcuch dwubajtowy. Następnie dwubajtowy łańcuch zostanie ponownie użyty do wstępnego obliczenia czterobajtowego łańcucha. Następnie czterobajtowy ciąg zostanie ponownie użyty, aby wstępnie obliczyć ośmiobajtowy ciąg. W końcu dwa ośmiobajtowe łańcuchy zostaną ponownie użyte, aby utworzyć pożądany nowy ciąg 16 bajtów. W sumie należało stworzyć cztery nowe struny, jeden o długości 2, jeden o długości 4, jeden o długości 8 i jeden o długości 16. Całkowity koszt wynosi 2 + 4 + 8 + 16 = 30.

Na dłuższą metę ta efektywność można obliczyć dodając w odwrotnej kolejności i używając szeregów geometrycznych zaczynających się od pierwszego terminu a1 = N i mających wspólny stosunek r = 1/2. Suma szeregu geometrycznego jest określona przez a_1 / (1-r) = 2N.

Jest to bardziej wydajne niż dodawanie jednego znaku, aby utworzyć nowy ciąg o długości 2, tworząc nowy ciąg o długości 3, 4, 5 i tak dalej, aż do 16. Poprzedni algorytm używał tego procesu dodawania pojedynczego bajtu na raz, a jego całkowity koszt wynosiłby n (n + 1) / 2 = 16 (17) / 2 = 8 (17) = 136.

Oczywiście, 136 jest znacznie większą liczbą niż 30, a więc poprzedni algorytm zajmuje znacznie, znacznie więcej czasu, aby zbudować ciąg znaków.

Aby porównać te dwie metody, możesz zobaczyć, o ile szybciej algorytm rekurencyjny (zwany także "divide and conquer") znajduje się na Ciągu o długości 123,457. Na moim komputerze FreeBSD algorytm ten, zaimplementowany w funkcji stringFill3(), tworzy łańcuch w 0.001058 sekund, podczas gdy oryginalna funkcja stringFill1() tworzy łańcuch w 0.0808 sekund. Nowa funkcja to 76 razy szybciej.

Różnica w wydajności rośnie wraz z długością łańcucha staje się większa. W limicie, gdy tworzone są coraz większe ciągi znaków, oryginalna funkcja zachowuje się mniej więcej jak C1 (stała) razy N^2, a nowa funkcja zachowuje się jak C2 (stała) razy N.

Z naszego eksperymentu możemy określić wartość C1 być C1 = 0.0808 / (123457)2 = .00000000000530126997, a wartość C2 być C2 = 0.001058 / 123457 = .00000000856978543136. W ciągu 10 sekund nowa funkcja może utworzyć ciąg zawierający 1,166,890,359 postaci. Aby utworzyć ten sam ciąg znaków, stara funkcja potrzebowałaby 7,218,384 sekund czasu.

To prawie trzy miesiące w porównaniu z dziesięcioma sekundami! [62]}odpowiadam tylko (kilka lat później), ponieważ moje oryginalne rozwiązanie tego problemu krąży po Internecie od ponad 10 lat i najwyraźniej nadal jest słabo zrozumiane przez niewielu, którzy go pamiętają. Myślałem, że pisząc artykuł o tym tutaj będę pomoc:

Optymalizacja wydajności dla szybkiego JavaScript / Strona 3

Niestety, niektóre z innych rozwiązań przedstawionych tutaj są nadal niektóre z tych, które zajęłyby trzy miesiące, aby uzyskać taką samą ilość produkcji, że odpowiednie rozwiązanie tworzy w 10 sekund.

Chcę poświęcić trochę czasu, aby odtworzyć część artykułu tutaj jako kanoniczną odpowiedź na Stack Overflow.

Zauważ, że najlepszy algorytm tutaj jest wyraźnie oparty na moim algorytm i został prawdopodobnie odziedziczony po czyjejś adaptacji trzeciej lub czwartej generacji. Niestety modyfikacje spowodowały zmniejszenie jego wydajności. Odmiana mojego rozwiązania przedstawiona tutaj być może nie zrozumiała mojego mylącego wyrażenia for (;;), które wygląda jak główna nieskończona pętla serwera napisanego w języku C, a które zostało po prostu zaprojektowane tak, aby umożliwić starannie ustawioną instrukcję break dla kontroli pętli, najbardziej kompaktowy sposób, aby uniknąć wykładniczo replikacji ciągu jeden dodatkowy niepotrzebny czas.

 43
Author: Joseph Myers,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-07-30 15:56:06

Ten jest całkiem wydajny

String.prototype.repeat = function(times){
    var result="";
    var pattern=this;
    while (times > 0) {
        if (times&1)
            result+=pattern;
        times>>=1;
        pattern+=pattern;
    }
    return result;
};
 39
Author: artistoex,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-11-11 08:39:17

Dobre wieści! String.prototype.repeat is accepted for Harmony (ECMAScript 6) .

> "yo".repeat(2)
"yoyo"

Metoda jest dostępna w najnowszych wersjach V8, używanych przez Node.js, Chrome (String.repeat Obsługiwane od wersji 41) i Opera. Nowsze wersje Safari i Firefox również wydają się mieć wsparcie, ale Internet Explorer nie. aby uzyskać aktualną listę, zobacz MDN: String.prototyp.repeat > Browser compatibility .

MDN proponuje następujący polyfill:

if (!String.prototype.repeat) {
  String.prototype.repeat = function(count) {
    'use strict';
    if (this == null) {
      throw new TypeError('can\'t convert ' + this + ' to object');
    }
    var str = '' + this;
    count = +count;
    if (count != count) {
      count = 0;
    }
    if (count < 0) {
      throw new RangeError('repeat count must be non-negative');
    }
    if (count == Infinity) {
      throw new RangeError('repeat count must be less than infinity');
    }
    count = Math.floor(count);
    if (str.length == 0 || count == 0) {
      return '';
    }
    // Ensuring count is a 31-bit integer allows us to heavily optimize the
    // main part. But anyway, most current (August 2014) browsers can't handle
    // strings 1 << 28 chars or longer, so:
    if (str.length * count >= 1 << 28) {
      throw new RangeError('repeat count must not overflow maximum string size');
    }
    var rpt = '';
    for (;;) {
      if ((count & 1) == 1) {
        rpt += str;
      }
      count >>>= 1;
      if (count == 0) {
        break;
      }
      str += str;
    }
    return rpt;
  }
}
 36
Author: André Laszlo,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-03-02 12:50:59

Sznurek.prototyp.repeat jest teraz standardem ES6.

'abc'.repeat(3); //abcabcabc
 18
Author: Lewis,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-04-07 04:33:16

Rozszerzenie rozwiązanie P. Baileya:

String.prototype.repeat = function(num) {
    return new Array(isNaN(num)? 1 : ++num).join(this);
    }

W ten sposób powinieneś być bezpieczny przed nieoczekiwanymi typami argumentów:

var foo = 'bar';
alert(foo.repeat(3));              // Will work, "barbarbar"
alert(foo.repeat('3'));            // Same as above
alert(foo.repeat(true));           // Same as foo.repeat(1)

alert(foo.repeat(0));              // This and all the following return an empty
alert(foo.repeat(false));          // string while not causing an exception
alert(foo.repeat(null));
alert(foo.repeat(undefined));
alert(foo.repeat({}));             // Object
alert(foo.repeat(function () {})); // Function

EDIT: Napisy dla jerone za swój elegancki ++num pomysł!

 17
Author: U-D13,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:34:59

Użyj Array(N+1).join("string_to_repeat")

 8
Author: Kalpesh Patel,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-08-21 06:33:41
/**  
@desc: repeat string  
@param: n - times  
@param: d - delimiter  
*/

String.prototype.repeat = function (n, d) {
    return --n ? this + (d || '') + this.repeat(n, d) : '' + this
};

W ten sposób powtarza się łańcuch kilka razy za pomocą delimetru.

 5
Author: BitOfUniverse,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-05-09 02:24:17

Oto 5-7% poprawa odpowiedzi disfated.

Rozwiń pętlę zatrzymując się na count > 1 i wykonaj dodatkowe result += pattnern concat po pętli. W ten sposób unikniemy pętli, które nie były wcześniej używane pattern += pattern bez konieczności używania drogiego if-check. Efekt końcowy wyglądałby tak:

String.prototype.repeat = function(count) {
    if (count < 1) return '';
    var result = '', pattern = this.valueOf();
    while (count > 1) {
        if (count & 1) result += pattern;
        count >>= 1, pattern += pattern;
    }
    result += pattern;
    return result;
};

A tu jest fiddle disfated for the unrolled version: http://jsfiddle.net/wsdfg/

 4
Author: Dennis,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-12-25 00:46:15
function repeat(s, n) { var r=""; for (var a=0;a<n;a++) r+=s; return r;}
 2
Author: Joel Coehoorn,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-10-14 20:17:15

Testy różnych metod:

var repeatMethods = {
    control: function (n,s) {
        /* all of these lines are common to all methods */
        if (n==0) return '';
        if (n==1 || isNaN(n)) return s;
        return '';
    },
    divideAndConquer:   function (n, s) {
        if (n==0) return '';
        if (n==1 || isNaN(n)) return s;
        with(Math) { return arguments.callee(floor(n/2), s)+arguments.callee(ceil(n/2), s); }
    },
    linearRecurse: function (n,s) {
        if (n==0) return '';
        if (n==1 || isNaN(n)) return s;
        return s+arguments.callee(--n, s);
    },
    newArray: function (n, s) {
        if (n==0) return '';
        if (n==1 || isNaN(n)) return s;
        return (new Array(isNaN(n) ? 1 : ++n)).join(s);
    },
    fillAndJoin: function (n, s) {
        if (n==0) return '';
        if (n==1 || isNaN(n)) return s;
        var ret = [];
        for (var i=0; i<n; i++)
            ret.push(s);
        return ret.join('');
    },
    concat: function (n,s) {
        if (n==0) return '';
        if (n==1 || isNaN(n)) return s;
        var ret = '';
        for (var i=0; i<n; i++)
            ret+=s;
        return ret;
    },
    artistoex: function (n,s) {
        var result = '';
        while (n>0) {
            if (n&1) result+=s;
            n>>=1, s+=s;
        };
        return result;
    }
};
function testNum(len, dev) {
    with(Math) { return round(len+1+dev*(random()-0.5)); }
}
function testString(len, dev) {
    return (new Array(testNum(len, dev))).join(' ');
}
var testTime = 1000,
    tests = {
        biggie: { str: { len: 25, dev: 12 }, rep: {len: 200, dev: 50 } },
        smalls: { str: { len: 5, dev: 5}, rep: { len: 5, dev: 5 } }
    };
var testCount = 0;
var winnar = null;
var inflight = 0;
for (var methodName in repeatMethods) {
    var method = repeatMethods[methodName];
    for (var testName in tests) {
        testCount++;
        var test = tests[testName];
        var testId = methodName+':'+testName;
        var result = {
            id: testId,
            testParams: test
        }
        result.count=0;

        (function (result) {
            inflight++;
            setTimeout(function () {
                result.start = +new Date();
                while ((new Date() - result.start) < testTime) {
                    method(testNum(test.rep.len, test.rep.dev), testString(test.str.len, test.str.dev));
                    result.count++;
                }
                result.end = +new Date();
                result.rate = 1000*result.count/(result.end-result.start)
                console.log(result);
                if (winnar === null || winnar.rate < result.rate) winnar = result;
                inflight--;
                if (inflight==0) {
                    console.log('The winner: ');
                    console.log(winnar);
                }
            }, (100+testTime)*testCount);
        }(result));
    }
}
 2
Author: Fordi,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-10-04 17:48:51

Oto bezpieczna wersja Jslinta

String.prototype.repeat = function (num) {
  var a = [];
  a.length = num << 0 + 1;
  return a.join(this);
};
 2
Author: Erik Aigner,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-05-09 02:15:45

Dla wszystkich przeglądarek

To jest tak zwięzłe, jak się wydaje:

function repeat(s, n) { return new Array(n+1).join(s); }

Jeśli zależy Ci również na wydajności, jest to znacznie lepsze podejście:

function repeat(s, n) { var a=[],i=0;for(;i<n;)a[i++]=s;return a.join(''); }

Jeśli chcesz porównać wydajność obu opcji, zobacz this Fiddle oraz this Fiddle do testów porównawczych. Podczas moich własnych testów druga opcja była około 2 razy szybsza w Firefoksie i około 4 razy szybciej w Chrome!

Tylko dla przeglądarek modern:

W nowoczesne przeglądarki, można teraz również zrobić to:

function repeat(s,n) { return s.repeat(n) };

Ta opcja jest nie tylko krótsza od obu innych opcji, ale jest jeszcze szybciej niż druga opcja.

Niestety, nie działa w żadnej wersji Internet Explorera. Liczby w tabeli określają pierwszą wersję przeglądarki, która w pełni obsługuje metodę:

Tutaj wpisz opis obrazka

 2
Author: John Slegers,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-02-25 18:06:26
function repeat(pattern, count) {
  for (var result = '';;) {
    if (count & 1) {
      result += pattern;
    }
    if (count >>= 1) {
      pattern += pattern;
    } else {
      return result;
    }
  }
}

Możesz go przetestować w JSFiddle . Benchmarked przeciwko hacky Array.join i mój jest, z grubsza rzecz biorąc, 10 (Chrome) do 100 (Safari) do 200 (Firefox) razy szybszy (w zależności od przeglądarki).

 2
Author: nikolay,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-03-24 04:24:13

Just another repeat function:

function repeat(s, n) {
  var str = '';
  for (var i = 0; i < n; i++) {
    str += s;
  }
  return str;
}
 2
Author: oboshto,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-01-28 00:36:23

ES2015 została zrealizowana ta metoda repeat()!

Http://www.ecma-international.org/ecma-262/6.0/#sec-string.prototype.repeat
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/repeat
http://www.w3schools.com/jsref/jsref_repeat.asp{[7]

/** 
 * str: String
 * count: Number
 */
const str = `hello repeat!\n`, count = 3;

let resultString = str.repeat(count);

console.log(`resultString = \n${resultString}`);
/*
resultString = 
hello repeat!
hello repeat!
hello repeat!
*/

({ toString: () => 'abc', repeat: String.prototype.repeat }).repeat(2);
// 'abcabc' (repeat() is a generic method)

// Examples

'abc'.repeat(0);    // ''
'abc'.repeat(1);    // 'abc'
'abc'.repeat(2);    // 'abcabc'
'abc'.repeat(3.5);  // 'abcabcabc' (count will be converted to integer)
// 'abc'.repeat(1/0);  // RangeError
// 'abc'.repeat(-1);   // RangeError
 2
Author: xgqfrms,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-06-30 14:38:21

To może być najmniejszy rekurencyjny: -

String.prototype.repeat = function(n,s) {
s = s || ""
if(n>0) {
   s += this
   s = this.repeat(--n,s)
}
return s}
 1
Author: John,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-07-02 14:54:55

Http://jsfiddle.net/3Y9v2/

function repeat(s, n){
    return ((new Array(n+1)).join(s));
}
alert(repeat('R', 10));
 1
Author: Robin Rizvi,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-08-05 09:57:10

Prosta konkatenacja rekurencyjna

Chciałem tylko dać mu bash, i zrobiłem to:

function ditto( s, r, c ) {
    return c-- ? ditto( s, r += s, c ) : r;
}

ditto( "foo", "", 128 );

Nie mogę powiedzieć, że dużo o tym myślałem, a to pewnie pokazuje : -)

to jest prawdopodobnie lepsze

String.prototype.ditto = function( c ) {
    return --c ? this + this.ditto( c ) : this;
};

"foo".ditto( 128 );

I to jest jak odpowiedź już wysłana - wiem o tym.

Ale po co w ogóle być rekurencyjnym?

A może trochę domyślnego zachowania?

String.prototype.ditto = function() {
    var c = Number( arguments[ 0 ] ) || 2,
        r = this.valueOf();
    while ( --c ) {
        r += this;
    }
    return r;
}

"foo".ditto();

Ponieważ, chociaż metoda nie rekurencyjna będzie obsługiwać arbitralnie Duże powtórzenia bez uderzania limitów stosu połączeń, jest o wiele wolniejszy.

Dlaczego zawracałem sobie głowę dodaniem kolejnych metod, które nie są w połowie tak sprytne jak te już opublikowane?

Częściowo dla własnej rozrywki, a częściowo dla podkreślenia w najprostszy sposób Wiem, że istnieje wiele sposobów na oskórowanie kota, i w zależności od sytuacji, jest całkiem możliwe, że pozornie najlepsza metoda nie jest idealna.

Stosunkowo szybka i wyrafinowana metoda może skutecznie i spalanie w pewnych okolicznościach, podczas gdy wolniejsza, prostsza metoda może wykonać zadanie-w końcu.

Niektóre metody mogą być niewiele więcej niż exploity, i jako takie podatne na istnieniestałe , a inne metody mogą działać pięknie w każdych warunkach, ale są tak skonstruowane, żeJEDEN {11]} po prostu nie ma pojęcia, jak to działa.

"co z tego, że nie wiem jak to działa?!"

Poważnie?

JavaScript cierpi na jedną z największych mocne strony; jest wysoce tolerancyjny na złe zachowanie i tak elastyczny, że pochyli się do tyłu, aby przywrócić wyniki, gdy byłoby lepiej dla wszystkich, gdyby pękł!

"z wielką mocą przychodzi wielka odpowiedzialność" ;-)

Ale bardziej poważnie i co najważniejsze, chociaż ogólne pytania takie jak to prowadzą do awesomeness w postaci sprytne odpowiedzi, że jeśli nic innego, poszerzyć swoją wiedzę i horyzonty, w końcu zadanie pod ręką-praktyczne skrypt wykorzystujący metodę wynikową-może wymagać trochę mniej, lub trochę więcej sprytnego niż jest to sugerowane.

Te"idealne" algorytmy są zabawne i w ogóle, ale"Jeden rozmiar dla wszystkich" rzadko, jeśli kiedykolwiek będzie lepszy niż szyty na miarę.

To kazanie zostało Ci dostarczone dzięki uprzejmości z braku snu i przemijającego zainteresowania. Idź i Szyfruj!

 1
Author: Fred Gandt,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-10-19 22:00:09

Po pierwsze, pytania OP wydają się być o zwięzłości - co rozumiem, że oznacza "proste i łatwe do odczytania", podczas gdy większość odpowiedzi wydają się być o wydajności - co oczywiście nie jest to samo, a także myślę, że jeśli nie wdrożyć niektóre bardzo specyficzne Duże algorytmy manipulacji danymi, nie powinno martwić, gdy przyjdziesz do wdrożenia podstawowych danych manipulacji funkcje Javascript. Zwięzłość jest o wiele ważniejsza.

Po drugie, jak zauważył André Laszlo, ciąg.powtórz to część ECMAScript 6 i już dostępna w kilku popularnych implementacjach - więc najbardziej zwięzłą implementacją String.repeat nie jest jej implementacja; -)

Wreszcie, jeśli potrzebujesz wsparcia dla hostów, które nie oferują implementacji ECMAScript 6, polyfill MDN wspomniany przez André Laszlo nie jest zwięzły.

Więc, bez zbędnych ceregieli - oto mój zwięzły polyfill:

String.prototype.repeat = String.prototype.repeat || function(n){
    return n<=1 ? this : this.concat(this.repeat(n-1));
}

Tak, to jest rekurencja. Lubię rekurencje - są proste i jeśli są wykonane poprawnie są łatwe do zrozumienia. Jeśli chodzi o efektywność, jeśli język ją wspiera, mogą być bardzo wydajne, jeśli są napisane poprawnie.

Z moich testów wynika, że ta metoda jest ~60% szybsza niż podejście Array.join. Choć oczywiście nie jest ona zbliżona do implementacji disfated, jest znacznie prostsza od obu.

Moja konfiguracja testowa to node v0.10, używający "Strict mode" (wydaje mi się, że włącza jakiś rodzaj TCO), wywołujący repeat(1000) Na ciągu znaków milion razy.

 1
Author: Guss,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-12-18 14:23:10

Użyj Lodash do obsługi JavaScript, np. powtarzających się łańcuchów.

Lodash zapewnia dobrą wydajność i kompatybilność z ECMAScript.

Gorąco polecam go do tworzenia interfejsu użytkownika i działa dobrze po stronie serwera.

Oto jak powtórzyć łańcuch "yo" 2 razy używając Lodash:

> _.repeat('yo', 2)
"yoyo"
 1
Author: l3x,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-11-04 19:55:11

Rozwiązanie rekurencyjne za pomocą divide and conquer:

function repeat(n, s) {
    if (n==0) return '';
    if (n==1 || isNaN(n)) return s;
    with(Math) { return repeat(floor(n/2), s)+repeat(ceil(n/2), s); }
}
 0
Author: Fordi,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-10-04 14:28:05

Przyszedłem tu przypadkowo i nigdy nie miałem powodu, aby powtarzać znak w javascript.

Byłem pod wrażeniem sposobu, w jaki artistoex to robi i zniekształcił wyniki. Zauważyłem, że ostatni concat strunowy był niepotrzebny, jak zauważył Dennis.

Zauważyłem jeszcze kilka rzeczy podczas zabawy z samplingiem disfated.

Wyniki różniły się znacznie, często faworyzując ostatni bieg i podobne algorytmy często atakowały pozycję. One of the things I zmieniono było zamiast używać jslitmus wygenerowany count jako zalążek dla wywołań; ponieważ count został wygenerowany inaczej dla różnych metod, wstawiłem indeks. Dzięki temu rzecz stała się bardziej niezawodna. Następnie spojrzałem na zapewnienie, że różne wielkości ciągów zostały przekazane do funkcji. Zapobiegło to niektórym wariacjom, które widziałem, gdzie niektóre algorytmy lepiej radziły sobie z pojedynczymi znakami lub mniejszymi łańcuchami. Jednak najlepsze metody 3 wszystko dobrze, niezależnie od rozmiaru łańcucha.

Test rozwidlenia set

Http://jsfiddle.net/schmide/fCqp3/134/

// repeated string
var string = '0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789';
// count paremeter is changed on every test iteration, limit it's maximum value here
var maxCount = 200;

var n = 0;
$.each(tests, function (name) {
    var fn = tests[name];
    JSLitmus.test(++n + '. ' + name, function (count) {
        var index = 0;
        while (count--) {
            fn.call(string.slice(0, index % string.length), index % maxCount);
            index++;
        }
    });
    if (fn.call('>', 10).length !== 10) $('body').prepend('<h1>Error in "' + name + '"</h1>');
});

JSLitmus.runAll();

Potem włączyłem poprawkę Dennisa i postanowiłem sprawdzić, czy mogę znaleźć sposób, aby poprawić trochę więcej.

Ponieważ javascript nie może naprawdę zoptymalizować rzeczy, najlepszym sposobem na poprawę wydajności jest ręczne unikanie rzeczy. Gdybym wziął pierwsze 4 trywialne wyniki z pętli, mógłbym uniknąć 2-4 sklepów ciągów i napisać końcowy sklep bezpośrednio do wyniku.

// final: growing pattern + prototypejs check (count < 1)
'final avoid': function (count) {
    if (!count) return '';
    if (count == 1) return this.valueOf();
    var pattern = this.valueOf();
    if (count == 2) return pattern + pattern;
    if (count == 3) return pattern + pattern + pattern;
    var result;
    if (count & 1) result = pattern;
    else result = '';
    count >>= 1;
    do {
        pattern += pattern;
        if (count & 1) result += pattern;
        count >>= 1;
    } while (count > 1);
    return result + pattern + pattern;
}

Spowodowało to 1-2% poprawę na średnio ponad Dennisa. Jednak różne wersje i różne przeglądarki wykazywałyby wystarczająco dużą wariancję, że ten dodatkowy kod prawdopodobnie nie jest wart wysiłku w porównaniu z poprzednimi algorytmami 2.

Wykres

Edit: robiłem to głównie pod chrome. Firefox i IE często faworyzują Dennisa o kilka %.

 0
Author: Andrew Hallendorff,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-03-15 04:21:30

Metoda prosta:

String.prototype.repeat = function(num) {
    num = parseInt(num);
    if (num < 0) return '';
    return new Array(num + 1).join(this);
}
 0
Author: Eduardo Cuomo,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-05-28 20:33:25

Ludzie przesadzają z tym w śmiesznym stopniu lub marnują wydajność. Tablice? Rekurencja? Chyba sobie żartujesz.

function repeat (string, times) {
  var result = ''
  while (times-- > 0) result += string
  return result
}

Edycja. przeprowadziłem kilka prostych testów, aby porównać wersję bitową opublikowaną przez artistoex / disfated i kilka innych osób. Ten ostatni był tylko nieznacznie szybszy, ale rzędy wielkości bardziej wydajny w pamięci. Dla 1000000 powtórzeń słowa "bla", proces węzła wzrósł do 46 megabajtów za pomocą prostego algorytmu konkatenacji (powyżej), ale tylko 5,5 megabajta z algorytmem logarytmicznym. Ta ostatnia jest zdecydowanie droga do zrobienia. Reposting it for the sake of clarity:

function repeat (string, times) {
  var result = ''
  while (times > 0) {
    if (times & 1) result += string
    times >>= 1
    string += string
  }
  return result
}
 0
Author: Nelo Mitranim,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-08-31 12:19:08

Jeśli uważasz, że wszystkie te definicje prototypów, tworzenie tablic i operacje łączenia są przesadą, po prostu użyj kodu z jednej linii tam, gdzie go potrzebujesz. String s powtarzający się N razy:

for (var i = 0, result = ''; i < N; i++) result += S;
 0
Author: Semra,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-01-25 12:13:58

Łączenie łańcuchów na podstawie liczby.

function concatStr(str, num) {
   var arr = [];

   //Construct an array
   for (var i = 0; i < num; i++)
      arr[i] = str;

   //Join all elements
   str = arr.join('');

   return str;
}

console.log(concatStr("abc", 3));
Mam nadzieję, że to pomoże!
 0
Author: Bishop,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-04-17 15:48:28