문자열 반복-Javascript


271

임의의 횟수로 반복되는 문자열을 반환하는 가장 좋고 가장 간결한 방법은 무엇입니까?

다음은 지금까지의 최고의 샷입니다.

function repeat(s, n){
    var a = [];
    while(a.length < n){
        a.push(s);
    }
    return a.join('');
}

5
10 년 전에이 문제에 대한 잘 알려진 해결책이 있었고이 질문을하기 몇 달 전에 JavaScript 최적화 기사에서 예제로 사용했습니다 : webreference.com/programming/javascript/jkm3/3 .html 분명히, 대부분의 사람들은 그 코드를 잊어 버렸고, 나만큼 좋은 솔루션은 보이지 않습니다. 가장 좋은 알고리즘은 내 코드에서 해제 된 것처럼 보입니다. 내 코드의 작동 방식에 대한 오해를 제외하고는 특별한 루프를 사용하여 원래의 코드에서 제거되는 지수 연결 단계를 한 단계 더 수행합니다.
Joseph Myers

10
아무도 요셉의 해결책을 들지 않았습니다. 알고리즘 은 3700 년입니다. 추가 단계 비용은 무시할 수 있습니다. 그리고 이 문서는 자바 스크립트에서 문자열 연결에 대한 오류와 오해가 포함되어 있습니다. Javascript가 실제로 문자열을 내부적으로 처리하는 방법에 관심이있는 사람은 Rope를 참조하십시오 .
artistoex

4
적어도 파이어 폭스에서 문자열 protoype 반복이 정의되고 구현 된 것을 아무도 알지 못했습니다.
kennebec

3
@ kennebec : 예,이 질문을 할 때 없었던 EcmaScript 6 기능입니다. 현재 상당히 잘 지원되고 있습니다.
rvighne

3
@rvighne-방금 kangax.github.io/compat-table/es6/#String.prototype.repeat를 확인 했습니다. 파이어 폭스와 크롬의 독점적 인 지원은 "정말 잘 지원됨"으로 간주되지 않습니다
aaaaaa

답변:


405

새로운 독자를위한 참고 사항 : 이 답변은 오래되었고별로 실용적이지 않습니다. String 일을하기 위해 Array 일을 사용하기 때문에 단지 "영리한"것입니다. "적은 프로세스"를 썼을 때 나는 다른 사람들이 후속 답변에서 언급했듯이 돼지처럼 작동하기 때문에 "적은 코드"를 의미했습니다. 따라서 속도가 중요한 경우에는 사용하지 마십시오.

이 함수를 String 객체에 직접 넣었습니다. 배열을 만들고 채우고 빈 문자로 결합하는 대신 적절한 길이의 배열을 만들고 원하는 문자열로 결합하십시오. 동일한 결과, 적은 프로세스!

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

alert( "string to repeat\n".repeat( 4 ) );

36
네이티브 객체를 확장하지 않으려 고하지만 그렇지 않으면 아름다운 솔루션입니다. 감사!
brad

34
@ 브래드-왜 안돼? 오히려 잘 정의 된 홈 (String 객체)이있는 함수로 전역 네임 스페이스를 오염시키고 싶습니까?
Peter Bailey

16
실제로, 두 인수 모두 전역 네임 스페이스에도 적용됩니다. 네임 스페이스를 확장하고 잠재적 충돌이 발생하는 경우 1) 전역이 아닌 2) 관련이있는 곳에서 3) 리팩토링하기 쉬운 것이 좋습니다. 이는 전역이 아닌 String 프로토 타입에 배치하는 것을 의미합니다.
Peter Bailey

11
이 함수에서 한 가지 변경은 parseInt ()를 "num"주위에 두는 것입니다. 숫자 문자열이 있으면 JS의 유형 저글링으로 인해 이상한 동작이 발생할 수 있습니다. 예를 들어 : "내 문자열".repeat ( "6") == "61"
nickf

19
기본 객체를 확장하지 않으려는 경우 대신 다음과 같이 함수를 String 객체에 배치 할 수 String.repeat = function(string, num){ return new Array(parseInt(num) + 1).join(string); };있습니다. 다음과 같이 호출하십시오.String.repeat('/\', 20)
Znarkus

203

제안 된 모든 접근 방식의 성능을 테스트했습니다.

가장 빠른 변형 은 다음과 같습니다 내가 가진 이 있습니다.

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;
};

또는 독립형 기능으로 :

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;
}

그것은 artistoex를 기반으로 합니다 알고리즘을 합니다. 정말 빠릅니다. 그리고가 클수록 count기존 new Array(count + 1).join(string)방식에 비해 빠릅니다 .

나는 단지 2 가지를 바꿨다.

  1. 교체 pattern = thispattern = this.valueOf()(클리어 한 명백한 형식 변환);
  2. 추가 된 if (count < 1)수표이 경우 불필요한 동작을 제외하기 위해 prototypejs 에서 함수 상단 .
  3. Dennis의 적용된 최적화 답변의 (5-7 % 속도 향상)

UPD

약간의 성능 테스트 놀이터를 만들었습니다. 여기를 사람들 관심이있는 사람들을 위해.

변수 count~ 0 .. 100 :

성능 다이어그램

상수 count= 1024 :

성능 다이어그램

가능하면 더 빨리 사용하십시오 :)


4
잘 하셨어요! 나는 그 count < 1경우가 정말로 불필요한 최적화 라고 생각합니다 .
JayVee

우수한 알고리즘 O (log N). valueOf ()와 큰 최적화를위한 감사합니다
vp_arth

2
이미지 링크가 죽었습니다.
Benjamin Gruenbaum

링크는 괜찮습니다. 일시적으로 사용할 수 없음
14 년

테스트 JSFiddle은 더 이상 올바르게 작동하지 않습니다. 첫 번째 기능을 계속 반복해서 실행하는 것 같습니다 (반드시 30 분 동안 계속 실행)
RevanProdigalKnight

47

이 문제는 JavaScript 문자열이 "불변"하고 단일 문자를 문자열에 연결하여 추가하기 위해 메모리 할당 및 복사를 포함하여 생성해야한다는 사실로 인해 JavaScript에 대해 잘 알려진 "고전적인"최적화 문제입니다. 완전히 새로운 문자열입니다.

불행히도이 페이지에서 허용되는 답변은 틀 렸습니다. 여기서 "잘못된"은 간단한 1 문자 문자열의 경우 3 배, 짧은 문자열의 경우 8x-97x, 여러 번 반복되는 문장의 경우 300x, 반복되는 문장의 경우 300x, 무한히 잘못된 경우 알고리즘의 복잡성 비율의 한계를 n 무한대 진행 합니다. 또한이 페이지에는 거의 올바른 대답이 있습니다 (지난 13 년 동안 인터넷을 통해 순환하는 올바른 솔루션의 많은 세대와 변형 중 하나를 기반으로 함). 그러나이 "가장 올바른"솔루션은 50 %의 성능 저하를 야기하는 올바른 알고리즘의 핵심 사항을 놓치고 있습니다.

허용 된 답변, 최고 성능의 다른 답변 (이 답변의 원래 알고리즘의 저하 된 버전을 기반으로 함) 및 13 년 전에 만든 내 알고리즘을 사용한이 답변에 대한 JS 성능 결과

~ 2000 년 10 월 나는이 정확한 문제에 대한 알고리즘을 발표했다.이 정확한 문제는 광범위하게 조정되고, 수정 된 다음, 이해하기 어려워졌다. 이 문제를 해결하기 위해 2008 년 8 월에 http://www.webreference.com/programming/javascript/jkm3/3.html 기사를 게시 하여 알고리즘을 설명하고 일반적인 JavaScript 최적화의 간단한 예로 사용했습니다. 지금까지 Web Reference 는이 기사에서 내 연락처 정보와 내 이름을 제거했습니다. 그리고 다시 한 번,이 알고리즘은 광범위하게 조정, 수정 된 후 이해력이 떨어지고 잊혀졌습니다.

Text.js 내의 텍스트 곱셈 함수로서 Y2K 경에 Joseph Myers의 원래 문자열 반복 / 곱셈 JavaScript 알고리즘; 2008 년 8 월 웹 참조에 의해이 형식으로 출판 : http://www.webreference.com/programming/javascript/jkm3/3.html (이 기사는이 기능을 JavaScript 최적화의 예로 사용했습니다. "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;
}

이 기사를 게시 한 후 2 개월 이내에이 같은 질문이 Stack Overflow에 게시되어 지금까지 내 레이더 아래로 날아갔습니다.이 문제에 대한 원래 알고리즘이 다시 한번 잊혀졌습니다. 이 Stack Overflow 페이지에서 사용 가능한 최상의 솔루션은 수정 된 버전의 솔루션으로, 여러 세대로 분리되어있을 수 있습니다. 불행히도 수정으로 솔루션의 최적 성이 손상되었습니다. 사실, 루프의 구조를 원래의 것에서 변경함으로써 수정 된 솔루션은 완전히 불필요한 불필요한 지수 복제 단계를 수행합니다 (따라서 정답에 사용 된 가장 큰 문자열을 자체적으로 추가 시간으로 결합 한 다음 버림).

아래는이 문제에 대한 모든 답변과 모든 사람의 이익을위한 일부 JavaScript 최적화에 대한 설명입니다.

기술 : 객체 또는 객체 속성에 대한 참조를 피하십시오

이 기법의 작동 방식을 설명하기 위해 필요한 길이의 문자열을 생성하는 실제 JavaScript 함수를 사용합니다. 앞으로 살펴 보 겠지만 더 많은 최적화를 추가 할 수 있습니다!

여기에 사용 된 것과 같은 기능은 텍스트 열을 정렬하거나 돈을 형식화하거나 블록 데이터를 경계까지 채우는 패딩을 만드는 것입니다. 텍스트 생성 기능은 텍스트에서 작동하는 다른 기능을 테스트하기 위해 가변 길이 입력을 허용합니다. 이 함수는 JavaScript 텍스트 처리 모듈의 중요한 구성 요소 중 하나입니다.

계속 진행하면서, 가장 중요한 최적화 기법 중 두 가지를 더 다루면서 원본 코드를 문자열 생성을위한 최적화 된 알고리즘으로 개발할 것입니다. 최종 결과는 JavaScript 주문 양식, 데이터 형식 및 전자 메일 / 문자 메시지 형식 및 기타 여러 용도로 항목 가격과 총계를 정렬하여 모든 곳에서 사용했던 강력한 산업용 고성능 기능입니다.

문자열을 만들기위한 원본 코드 stringFill1()

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

구문은 명확합니다. 보시다시피, 우리는 더 많은 최적화를 진행하기 전에 이미 지역 함수 변수를 사용했습니다.

s.length코드에서 성능을 저하 시키는 객체 속성 에 대한 하나의 무고한 참조가 있음에 유의하십시오 . 더 나쁜 것은이 객체 속성을 사용하면 독자가 JavaScript 문자열 객체의 속성에 대해 알고 있다고 가정함으로써 프로그램의 단순성을 줄입니다.

이 개체 속성을 사용하면 컴퓨터 프로그램의 일반성이 손상됩니다. 프로그램은 x길이가 1 인 문자열이어야 한다고 가정 합니다. 이것은 stringFill1()단일 문자의 반복을 제외한 모든 것에 대한 기능 적용을 제한합니다 . HTML 엔터티와 같이 여러 바이트가 포함 된 단일 문자도 사용할 수 없습니다 &nbsp;.

이 불필요한 객체 속성 사용으로 인한 최악의 문제는 빈 입력 문자열에서 테스트하면 함수가 무한 루프를 생성한다는 것입니다 x 입니다. 일반성을 확인하려면 가능한 가장 적은 양의 입력에 프로그램을 적용하십시오. 사용 가능한 메모리 양을 초과하라는 메시지가 표시되면 프로그램이 중단됩니다. 아무것도 생성하지 않을 때 충돌하는 이와 같은 프로그램은 허용되지 않습니다. 때때로 예쁜 코드는 유독 한 코드입니다.

단순성은 컴퓨터 프로그래밍의 모호한 목표 일 수 있지만 일반적으로 그렇지 않습니다. 프로그램에 합리적인 수준의 일반성이 없으면 "프로그램이 진행되는 한 충분합니다."라고 말하는 것은 유효하지 않습니다. 보시 string.length다시피이 속성을 사용하면이 프로그램이 일반 설정에서 작동하지 않으며 실제로 잘못된 프로그램이 브라우저 나 시스템 충돌을 일으킬 수 있습니다.

이 JavaScript의 성능을 향상시키고이 두 가지 심각한 문제를 처리 할 수있는 방법이 있습니까?

물론이야. 정수만 사용하십시오.

문자열 생성을위한 최적화 된 코드 stringFill2()

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

코드를 타이밍하는 것은 비교하기 stringFill1()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); 

지금까지의 성공 stringFill2()

stringFill1()100 바이트 문자열을 채우려면 47.297 마이크로 초 (백만 분의 1 초)가 stringFill2()걸리고 같은 작업을 수행하려면 27.68 마이크로 초가 걸립니다. 객체 속성에 대한 참조를 피함으로써 성능이 거의 두 배가됩니다.

기술 : 긴 문자열에 짧은 문자열을 추가하지 마십시오

우리의 이전 결과는 실제로 매우 좋았습니다. 개선 된 기능 stringFill2()은 처음 두 가지 최적화를 사용하기 때문에 훨씬 빠릅니다. 지금보다 몇 배나 더 빨리 개선 될 수 있다고 말하면 믿을 수 있습니까?

우리는 그 목표를 달성 할 수 있습니다. 지금은 긴 문자열에 짧은 문자열을 추가하지 않는 방법을 설명해야합니다.

단기적인 행동은 원래의 기능과 비교할 때 상당히 좋은 것으로 보입니다. 컴퓨터 과학자들은 함수 또는 컴퓨터 프로그램 알고리즘의 "점근 적 행동"을 분석하는 것을 좋아하는데, 이는 더 큰 입력으로 테스트하여 장기적인 행동을 연구하는 것을 의미합니다. 때때로 추가 테스트를 수행하지 않으면 컴퓨터 프로그램을 개선 할 수있는 방법을 결코 알지 못합니다. 어떤 일이 발생하는지 확인하기 위해 200 바이트 문자열을 만들 것입니다.

와 함께 나타나는 문제 stringFill2()

타이밍 함수를 사용하면 200 바이트 문자열의 경우 시간이 100 바이트 문자열의 27.68에 비해 62.54 마이크로 초로 증가합니다. 두 배나 많은 작업을 수행하려면 시간을 두 배로 늘려야하는 것처럼 보이지만 세 배나 네 배로 늘어납니다. 프로그래밍 경험에서 볼 때이 결과는 이상하게 보입니다. 어떤 것이라도 작업이보다 효율적으로 수행되기 때문에 함수가 약간 더 빨라야하기 때문입니다 (함수 호출 당 100 바이트가 아니라 함수 호출 당 200 바이트). 이 문제는 JavaScript 문자열의 교활한 속성과 관련이 있습니다. JavaScript 문자열은 "불변"입니다.

불변은 문자열을 만든 후에는 변경할 수 없음을 의미합니다. 한 번에 하나의 바이트를 추가함으로써 하나의 바이트 노력을 더 이상 사용하지 않습니다. 우리는 실제로 전체 문자열과 하나 이상의 바이트를 다시 만들고 있습니다.

실제로 100 바이트 문자열에 1 바이트를 더 추가하려면 101 바이트의 작업이 필요합니다. N바이트 문자열을 만들기위한 계산 비용을 간단히 분석해 봅시다 . 첫 번째 바이트를 추가하는 비용은 1 단위의 계산 노력입니다. 두 번째 바이트를 추가하는 비용은 한 단위가 아니라 2 단위입니다 (두 번째 바이트를 추가 할뿐만 아니라 첫 번째 바이트를 새 문자열 객체에 복사). 세 번째 바이트는 3 단위의 비용이 필요합니다.

C(N) = 1 + 2 + 3 + ... + N = N(N+1)/2 = O(N^2). 이 기호 O(N^2)는 Big O of N squared로 발음되며 장기적으로 계산 비용이 문자열 길이의 제곱에 비례한다는 것을 의미합니다. 100자를 만들려면 10,000 단위의 작업이 필요하고 200자를 만들려면 40,000 단위의 작업이 필요합니다.

이것이 100 자보다 200자를 만드는 데 두 배 이상 걸린 이유입니다. 실제로 4 배나 오래 걸렸습니다. 우리의 프로그래밍 경험은 더 긴 문자열을 위해 작업이 약간 더 효율적으로 수행되고 있다는 점에서 정확하므로 약 3 배의 시간이 걸렸습니다. 함수 호출의 오버 헤드가 생성하는 문자열의 길이에 대해 무시할 수있게되면 실제로 문자열을 두 배로 만드는 데 4 배의 시간이 걸립니다.

(역사적 주 : html = 'abcd\n' + 'efgh\n' + ... + 'xyz.\n'JavaScript 소스 코드 컴파일러는 문자열을 JavaScript 문자열 객체로 만들기 전에 함께 결합 할 수 있기 때문에 소스 코드의 문자열에는이 분석이 반드시 적용되는 것은 아닙니다 . 불과 몇 년 전 KJS 구현은 더하기 부호로 결합 된 긴 소스 코드 문자열을로드 할 때 JavaScript가 중단되거나 중단되는 경우 계산 시간이 O(N^2)지나서 Konqueror 웹 브라우저 또는 KJS JavaScript 엔진 코어를 사용하는 Safari에 과부하가 걸리는 웹 페이지를 만드는 것은 어렵지 않았습니다. 마크 업 언어 및 JavaScript 마크 업 언어 파서를 개발할 때이 문제가 발생했으며 JavaScript Includes 용 스크립트를 작성할 때 문제의 원인을 발견했습니다.)

이처럼 빠른 성능 저하는 큰 문제입니다. JavaScript를 사용하여 문자열을 변경 불가능한 객체로 처리하는 방법을 변경할 수 없다면 어떻게 처리 할 수 ​​있습니까? 해결책은 문자열을 가능한 한 몇 번 재생성하는 알고리즘을 사용하는 것입니다.

명확히하기 위해, 우리의 목표는 짧은 문자열을 긴 문자열에 추가하는 것을 피하는 것입니다. 짧은 문자열을 추가하려면 전체 긴 문자열도 복제해야하기 때문입니다.

긴 문자열에 짧은 문자열을 추가하지 않도록 알고리즘이 작동하는 방식

새로운 문자열 객체가 생성되는 횟수를 줄이는 좋은 방법이 있습니다. 한 번에 둘 이상의 바이트가 출력에 추가되도록 더 긴 길이의 문자열을 함께 연결하십시오.

예를 들어, 길이가 문자열 인 경우 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 */

이렇게하려면 길이가 1 인 문자열을 만들고 길이가 2 인 문자열을 만들고 길이가 4 인 문자열을 만들고 길이가 8 인 문자열을 만들고 마지막으로 길이가 9 인 문자열을 만들어야했습니다. 비용은 얼마입니까?

이전 비용 C(9) = 1 + 2 + 3 + 4 + 5 + 6 + 7 + 9 = 45.

새로운 비용 C(9) = 1 + 2 + 4 + 8 + 9 = 24.

길이 1의 문자열을 길이 0의 문자열에 추가 한 다음 길이 1의 문자열을 길이 1의 문자열에 추가 한 다음 길이 2의 문자열을 길이 2의 문자열, 길이 4의 문자열을 추가해야합니다. 길이가 9 인 문자열을 얻기 위해 길이가 4 인 문자열, 길이가 8 인 문자열, 길이가 1 인 문자열을 비교합니다. 우리가하고있는 일은 긴 문자열에 짧은 문자열을 추가하지 않는 것으로 요약 할 수 있습니다. 길이가 같거나 거의 같은 문자열을 함께 연결하려고합니다.

이전 계산 비용으로 우리는 공식을 찾았습니다 N(N+1)/2. 새로운 비용에 대한 공식이 있습니까? 예,하지만 복잡합니다. 중요한 것은 O(N)문자열 길이를 두 배로 늘리면 작업량을 네 배로 늘리지 않고 작업량을 약 두 배로 늘릴 수 있다는 것입니다 .

이 새로운 아이디어를 구현하는 코드는 계산 비용에 대한 공식만큼이나 복잡합니다. 읽을 때 >>= 11 바이트 씩 오른쪽으로 이동 한다는 것을 기억하십시오 . 따라서 n = 10011이진수 n >>= 1이면 값이 n = 1001됩니다.

인식하지 못하는 코드의 다른 부분은 비트 단위 및 연산자입니다 &. 식은 n & 1마지막 이진수 n가 1 이면 true를 평가 하고 마지막 이진수 n가 0이면 false를 평가합니다 .

새로운 고효율 stringFill3()기능

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

훈련받지 않은 눈에는보기에 좋지 않지만 성능은 그저 사랑 스럽습니다.

이 기능이 얼마나 잘 수행되는지 봅시다. 결과를 본 후에는 O(N^2)알고리즘과 알고리즘 의 차이점을 잊지 못할 것 O(N)입니다.

stringFill1()200 바이트 문자열을 만드는 데 88.7 마이크로 초 (백만 분의 1 초)가 stringFill2()걸리고 62.54가 걸리며 4.608 stringFill3()만 걸립니다. 이 알고리즘이 훨씬 더 나은 이유는 무엇입니까? 모든 함수는 로컬 함수 변수를 사용하는 이점을 얻었지만 두 번째 및 세 번째 최적화 기술을 활용하면의 성능이 20 배 향상되었습니다 stringFill3().

심층 분석

이 특별한 기능이 물에서 경쟁을 불러 일으키는 이유

앞에서 언급했듯이이 두 함수 stringFill1()stringFill2()가 느리게 실행 되는 이유 는 JavaScript 문자열을 변경할 수 없기 때문입니다. JavaScript로 저장된 문자열 데이터에 한 번에 하나 이상의 바이트를 추가 할 수 있도록 메모리를 재 할당 할 수 없습니다. 하나의 바이트가 문자열의 끝에 추가 될 때마다 전체 문자열이 처음부터 끝까지 재생성됩니다.

따라서 스크립트의 성능을 향상 시키려면 두 개의 문자열을 미리 연결 한 다음 원하는 문자열 길이를 재귀 적으로 작성하여 더 긴 문자열을 미리 계산해야합니다.

예를 들어 16 자 바이트 문자열을 만들려면 먼저 2 바이트 문자열이 미리 계산됩니다. 그런 다음 2 바이트 문자열을 다시 사용하여 4 바이트 문자열을 사전 계산합니다. 그런 다음 4 바이트 문자열을 다시 사용하여 8 바이트 문자열을 사전 계산합니다. 마지막으로, 2 바이트의 8 바이트 문자열을 재사용하여 원하는 새 16 바이트 문자열을 작성합니다. 전체 길이는 2 + 4 + 8 + 16 = 30입니다. 총 길이는 2 + 4 + 8 + 16 = 30입니다.

장기적으로이 효율성은 역순으로 추가하고 첫 번째 항 a1 = N으로 시작하고 r = 1/2의 공통 비율을 갖는 기하 계열을 사용하여 계산할 수 있습니다. 기하 계열의 합은로 주어집니다 a_1 / (1-r) = 2N.

16 자까지 길이가 3, 4, 5 등인 새 문자열을 작성하기 위해 문자 하나를 추가하여 길이 2의 새 문자열을 작성하는 것보다 효율적입니다. 이전 알고리즘은 한 번에 단일 바이트를 추가하는 프로세스를 사용했습니다. 총 비용은입니다 n (n + 1) / 2 = 16 (17) / 2 = 8 (17) = 136.

분명히 136은 30보다 훨씬 많으므로 이전 알고리즘은 문자열을 작성하는 데 훨씬 더 많은 시간이 걸립니다.

두 방법을 비교하기 위해 재귀 알고리즘 ( "분할 및 정복"이라고도 함)이 길이가 123,457 인 문자열의 속도가 훨씬 빠릅니다. 내 FreeBSD 컴퓨터에서 stringFill3()함수에 구현 된이 알고리즘 은 0.001058 초 안에 문자열을 생성하는 반면, 원래 stringFill1()함수는 0.0808 초 안에 문자열을 생성합니다. 새로운 기능은 76 배 더 빠릅니다.

줄 길이가 길어질수록 성능 차이가 커집니다. 더 크고 더 큰 문자열이 만들어 질 때의 한계에서 원래 함수는 C1(일정한) 시간 과 거의 비슷하게 작동 N^2하고 새 함수는 C2(일정한) 시간 과 같이 작동 N합니다.

우리의 실험에서 우리는의 가치를 결정할 수 C1있을하는 C1 = 0.0808 / (123457)2 = .00000000000530126997, 그리고 값 C2이 될을 C2 = 0.001058 / 123457 = .00000000856978543136. 10 초 안에 새 함수는 1,166,890,359자를 포함하는 문자열을 만들 수 있습니다. 동일한 문자열을 만들려면 이전 함수에 7,218,384 초의 시간이 필요합니다.

이것은 10 초에 비해 거의 3 개월입니다!

이 문제에 대한 나의 원래의 해결책이 인터넷에 10 년 넘게 떠 올랐고, 아직도 그것을 기억하는 소수의 사람들은 여전히 ​​잘 이해하지 못했기 때문에 나는 (몇 년 늦게) 대답하고 있습니다. 여기에 기사를 쓰면 도움이 될 것이라고 생각했습니다.

고속 JavaScript를위한 성능 최적화 / 3 페이지

불행히도, 여기에 제시된 다른 솔루션 중 일부는 여전히 적절한 솔루션이 10 초 안에 생성하는 동일한 양의 출력을 생성하는 데 3 개월이 걸리는 솔루션 중 일부입니다.

여기에서 기사의 일부를 스택 오버플로에 대한 정식 답변으로 재현하는 데 시간을 갖고 싶습니다.

여기서 최고의 성능을내는 알고리즘은 내 알고리즘을 기반으로하며 다른 사람의 3 세대 또는 4 세대 적응에서 상속되었을 수 있습니다. 불행히도 수정으로 인해 성능이 저하되었습니다. 여기에 제시된 솔루션의 변형은 아마도 for (;;)C로 작성된 서버의 주요 무한 루프처럼 보이고 혼란스러운 표현을 이해하지 못했을 것 입니다. 불필요한 불필요한 시간을 문자열로 기하 급수적으로 복제하지 마십시오.


4
이 답변은 많은 찬사를받지 않아야합니다. 우선, Joseph의 소유권 주장은 ridiculuou입니다. 기본 알고리즘 은 3700 년입니다.
artistoex

2
둘째, 많은 잘못된 정보가 포함되어 있습니다. 현대 Javascript 구현은 연결을 수행 할 때 문자열의 내용을 건드리지 않습니다 (v8은 연결된 문자열을 ConsString 유형의 객체로 나타냄). 나머지 모든 개선 사항은 무시할 수 있습니다 (점근 적 복잡성 측면에서).
artistoex

3
문자열이 어떻게 연결되는지에 대한 당신의 생각이 잘못되었습니다. 두 문자열을 연결하기 위해 Javascript는 구성 문자열의 바이트를 전혀 읽지 않습니다. 대신 왼쪽과 오른쪽 부분을 참조하는 개체를 만듭니다. 이것이 루프의 마지막 연결이 첫 번째 연결보다 더 비싸지 않은 이유입니다.
artistoex

3
물론, 이로 인해 문자열 인덱싱에 O (1)보다 큰 비용이 발생하므로 연결이 나중에 평평 해 지므로 추가 평가가 필요합니다.
artistoex

1
이것은 훌륭한 독서였습니다. 효율성과 그 모든 것에 관한 책을 써야합니다!

39

이것은 매우 효율적입니다

String.prototype.repeat = function(times){
    var result="";
    var pattern=this;
    while (times > 0) {
        if (times&1)
            result+=pattern;
        times>>=1;
        pattern+=pattern;
    }
    return result;
};

11
@Olegs, 나는 투표의 아이디어가 사람이나 사람의 창의성에 대한 투표보다 적다고 생각하지만 (실제로 박수를 보낼 수 있음) 아이디어는 가장 완벽한 솔루션에 투표하여 쉽게 찾을 수 있습니다. 완벽한 답변을 찾기 위해 모든 답변을 읽을 필요없이 목록의 맨 위에 있습니다. (불행하게도, 우리는 시간이 제한되어 있기 때문에 ...)
소린 포스텔 니쿠

38

좋은 소식! String.prototype.repeat입니다 지금은 자바 스크립트의 일부 .

"yo".repeat(2);
// returns: "yoyo"

이 방법은 Internet Explorer 및 Android Webview를 제외한 모든 주요 브라우저에서 지원됩니다. 최신 목록은 MDN : String.prototype.repeat> 브라우저 호환성을 참조하십시오 .

MDN에는 지원하지 않는 브라우저를위한 폴리 필 이 있습니다.


모니카 폴리 필은 대부분의 요구에 대해 매우 복잡하다고 생각하지만 (현재 C 구현의 효율적인 동작을 모방하려고한다고 가정합니다) 간결성에 대한 OP의 요구 사항에 실제로 대답하지는 않습니다. polyfill으로 설정된 다른 접근 방식은보다 간결해야합니다. ;-)
Guss

2
명확히! 그러나 내장을 사용하는 것이 가장 간결한 버전이어야합니다. 폴리 필은 기본적으로 백 포트이므로 스펙 (또는이 경우 제안 된 스펙)과의 호환성을 보장하기에는 약간 복잡합니다. 나는 완전성을 위해 그것을 추가했다. 사용할 방법을 결정하는 것은 OP에 달려있다.
André Laszlo


17

P.Bailey의 솔루션 확장 :

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

이렇게하면 예기치 않은 인수 유형으로부터 안전해야합니다.

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

편집 : 그의 우아한 아이디어에 대해 위안주는 크레딧 ++num!


2
당신의 작은 변경 :String.prototype.repeat = function(n){return new Array(isNaN(n) ? 1 : ++n).join(this);}
jerone

어쨌든이 테스트 ( jsperf.com/string-repeat/2 ) 에 따르면 String 연결 로 간단한 for 루프를 수행하는 것은 Array.join을 사용하는 것보다 Chrome에서 훨씬 빠릅니다. 재미 있지 않나요?!
Marco Demaio

8

사용하다 Array(N+1).join("string_to_repeat")


나는 이것을 좋아한다. 왜 거기에 있지 않은지 Idk.
Joe Thomas

그것을 사랑하십시오. 너무 간단하고 깨끗합니다
ekkis

5
/**  
@desc: repeat string  
@param: n - times  
@param: d - delimiter  
*/

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

이것은 delimeter를 사용하여 문자열을 여러 번 반복하는 방법입니다.


4

disfated의 답변이 5-7 % 향상되었습니다.

에서 중지 하고 루프 이후에 count > 1추가 result += pattnern연결을 수행 하여 루프를 언롤하십시오 . 이렇게하면 pattern += pattern값 비싼 if-check를 사용 하지 않고 이전에 사용 하지 않은 루프의 최종 결과를 피할 수 있습니다. 최종 결과는 다음과 같습니다.

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;
};

그리고 unrolled 버전을 위해 disfated의 바이올린 포크가 있습니다 : http://jsfiddle.net/wsdfg/


2
function repeat(s, n) { var r=""; for (var a=0;a<n;a++) r+=s; return r;}

2
문자열 연결에 많은 비용이 듭니까? 적어도 Java의 경우입니다.
Vijay Dev

왜 그래요? 그러나 javarscript에서는 실제로 최적화 할 수 없습니다. :(
McTrafik

var r=s; for (var a=1;...어쨌든 이 성능 향상에 대한 것 : :)))) 어쨌든이 테스트 ( jsperf.com/string-repeat/2 ) 에 따르면 제안한 것과 같은 문자열 연결로 간단한 for 루프를 수행하면 배열을 사용하는 것보다 Chrome에서 더 빠릅니다. .붙다.
Marco Demaio

@VijayDev-이 테스트에 따르지 않음 : jsperf.com/ultimate-concat-vs-join
jbyrd

2

다양한 방법의 테스트 :

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

다음은 JSLint 안전 버전입니다

String.prototype.repeat = function (num) {
  var a = [];
  a.length = num << 0 + 1;
  return a.join(this);
};

2

모든 브라우저

이것은 얻을만큼 간결합니다.

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

성능에 관심이 있다면 훨씬 더 나은 방법입니다.

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

당신이 두 옵션의 성능을 비교할 경우, 볼 이 바이올린이 바이올린을 벤치 마크 테스트를 위해. 내 자신의 테스트 중에 두 번째 옵션은 Firefox에서 약 2 배 빠르며 Chrome에서는 약 4 배 빠릅니다!

최신 브라우저 만 해당 :

최신 브라우저에서 이제 다음을 수행 할 수도 있습니다.

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

이 옵션은 다른 두 옵션보다 짧을뿐만 아니라 두 번째 옵션보다 훨씬 빠릅니다 .

불행히도 어떤 버전의 Internet Explorer에서도 작동하지 않습니다. 표의 숫자는 메소드를 완전히 지원하는 첫 번째 브라우저 버전을 지정합니다.

여기에 이미지 설명을 입력하십시오



2

또 다른 반복 기능 :

function repeat(s, n) {
  var str = '';
  for (var i = 0; i < n; i++) {
    str += s;
  }
  return str;
}

2

ES2015repeat()방법 이 실현되었습니다 !

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/ 문자열 / 반복
http://www.w3schools.com/jsref/jsref_repeat.asp

/** 
 * 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


1

이것은 가장 작은 재귀 적 일 수 있습니다.

String.prototype.repeat = function(n,s) {
s = s || ""
if(n>0) {
   s += this
   s = this.repeat(--n,s)
}
return s}


1

간단한 재귀 연결

방금 bash를 만들고 싶었습니다.

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

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

나는 그것을 많이 생각했다고 말할 수 없으며 아마도 아마 :-)를 보여줍니다.

이것은 틀림없이 더 낫다

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

"foo".ditto( 128 );

그리고 그것은 이미 게시 된 답변과 매우 비슷합니다.

그러나 왜 재귀 적입니까?

그리고 약간의 기본 행동도 어떻습니까?

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

"foo".ditto();

때문에 비 재귀 방법은 호출 스택 제한을 타격하지 않고 임의의 큰 반복을 처리 할 수 있지만, 그것은 훨씬 더 느리다.

영리 하지 않은 방법을 더 추가해야합니까? 이미 게시 된 것 해야합니까?

부분적으로는 내 자신의 즐거움을 위해, 그리고 가장 간단한 방법으로 고양이를 껍질을 벗기는 방법이 많이 있다는 것을 알고 있으며, 상황에 따라 분명히 가장 좋은 방법이 이상적이지 않을 수 있습니다.

상대적으로 빠르고 정교한 방법은 특정 상황에서 효과적으로 충돌하고 타는 반면, 더 느리고 간단한 방법은 결국 작업을 수행 할 수 있습니다.

일부 방법은 익스플로잇에 지나지 않으며 존재하지 않는 상태로 고정 되는 경향이 있으며 , 다른 방법은 모든 조건에서 아름답게 작동 할 수 있지만 그 중 하나는 단순히 그것이 어떻게 작동하는지 아무 생각이 없습니다.

"어떻게 작동하는지 모르겠다면?"

진심이야?

JavaScript는 가장 큰 장점 중 하나를 겪고 있습니다. 그것은 나쁜 행동에 매우 견딜 수 있으며, 너무 유연하여 뒤로 밀려서 결과를 반환 할 수 있습니다.

"큰 힘으로 큰 책임을진다" ;-)

그러나 더 심각하고 중요한 것은,이 같은 일반적인 질문의 형태로 awesomeness에 이어질 않지만 영리한 답변 다른 것도, 자신의 지식과 시야를 확장하지 않는 경우가 결국 손에있는 작업 표시 - 실제 스크립트 그 사용 결과 방법 - 조금 더 적거나 더 영리한 것이 필요할 수 있습니다. 제안 된 것보다 것이 .

"완벽한" 알고리즘은 재미 있고 모든 것이지만, "하나의 크기에 모두 맞는 " 알고리즘은 맞춤식보다 더 나은 경우는 거의 없습니다.

이 설교는 수면 부족과 지나친 관심으로 호의를 얻었습니다. 코드를 작성하십시오!


1

첫째, OP의 질문은 간결함에 관한 것 같습니다- "간단하고 읽기 쉬운"을 의미하는 것으로 이해하지만 대부분의 답변은 효율성에 관한 것 같습니다-이것은 분명히 같은 것이 아니며 또한 일부를 구현하지 않으면 특정 대규모 데이터 조작 알고리즘을 사용하면 기본 데이터 조작 Javascript 함수를 구현할 때 걱정하지 않아도됩니다. 간결함이 훨씬 더 중요합니다.

두 번째로 André Laszlo가 지적했듯이 String.repeat는 ECMAScript 6의 일부이며 이미 널리 사용되는 여러 구현에서 사용할 수 있습니다. 따라서 가장 간결한 구현은 구현 String.repeat하지 않는 것입니다. ;-)

마지막으로 ECMAScript 6 구현을 제공하지 않는 호스트를 지원해야하는 경우 André Laszlo가 언급 한 MDN의 polyfill은 간결합니다.

따라서 더 이상 고민하지 않고 여기에 간결한 polyfill이 있습니다.

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

예, 이것은 재귀입니다. 나는 재귀를 좋아한다-그것들은 간단하고 올바르게 수행되면 이해하기 쉽다. 효율성과 관련하여 언어가 지원하는 언어는 올바르게 작성하면 매우 효율적일 수 있습니다.

내 테스트 에서이 방법은 Array.join접근법 보다 ~ 60 % 빠릅니다 . 명백하게 disfated의 구현은 어디에도 없지만, 둘 다보다 훨씬 간단합니다.

내 테스트 설정은 "엄격 모드"(일부 종류의 TCO 사용 가능 ) repeat(1000)를 사용하여 10 자 문자열을 백만 번 호출 하는 노드 v0.10 입니다.


1

이러한 모든 프로토 타입 정의, 어레이 생성 및 조인 작업이 과도하다고 생각되면 필요한 경우 단일 라인 코드를 사용하십시오. N 번 반복되는 문자열 S :

for (var i = 0, result = ''; i < N; i++) result += S;

3
코드를 읽을 수 있어야합니다. 말 그대로 모든 것을 한 번만 사용하려는 경우 올바르게 형식을 지정하십시오 (또는 Array(N + 1).join(str)성능 병목 현상이 아닌 경우 방법을 사용하십시오 ). 두 번 사용할 확률이 가장 적다면 적절한 이름의 함수로 옮기십시오.
cloudfeet 2016 년

1

반복 문자열과 같은 Javascript 유틸리티 기능에 Lodash를 사용하십시오.

Lodash는 뛰어난 성능과 ECMAScript 호환성을 제공합니다.

UI 개발을 위해 강력히 권장하며 서버 측에서도 잘 작동합니다.

Lodash를 사용하여 문자열 "yo"를 두 번 반복하는 방법은 다음과 같습니다.

> _.repeat('yo', 2)
"yoyo"

0

나누기와 정복을 사용한 재귀 솔루션 :

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

나는 무작위로 여기에 왔으며 전에 자바 스크립트에서 문자를 반복 할 이유가 없었습니다.

나는 artistoex의 작업 방식과 disfated의 결과에 깊은 인상을 받았습니다. Dennis도 지적했듯이 마지막 문자열 연결이 불필요하다는 것을 알았습니다.

나는 샘플링 disfated와 함께 연주 할 때 몇 가지 더 주목했습니다.

결과는 종종 마지막 실행을 선호하는 상당한 양을 변화 시켰으며 유사한 알고리즘이 종종 위치를 기수하는 경우도있었습니다. 내가 바꾼 것들 중 하나는 JSLitmus 생성 카운트를 호출의 시드로 사용하는 것이 아니라; 다양한 방법에 대해 카운트가 다르게 생성되었으므로 색인을 작성했습니다. 이것은 훨씬 더 안정적인 것을 만들었습니다. 그런 다음 다양한 크기의 문자열이 함수에 전달되는지 확인했습니다. 이것은 내가 본 변형 중 일부를 막았습니다. 여기서 일부 알고리즘은 단일 문자 또는 작은 문자열에서 더 좋았습니다. 그러나 상위 3 가지 방법은 모두 문자열 크기에 관계없이 잘 수행되었습니다.

갈래 테스트 세트

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();

그런 다음 Dennis의 수정 사항을 포함시키고 조금 더 이길 방법을 찾을 수 있는지 결정했습니다.

자바 스크립트는 실제로 최적화 할 수 없으므로 성능을 개선하는 가장 좋은 방법은 수동으로 방지하는 것입니다. 루프에서 첫 번째 사소한 결과를 취하면 2-4 개의 문자열 저장소를 피하고 최종 저장소를 결과에 직접 쓸 수 있습니다.

// 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;
}

이로 인해 Dennis의 수정보다 평균 1-2 % 개선되었습니다. 그러나 다른 실행과 다른 브라우저는이 여분의 코드가 이전의 2 개 알고리즘보다 노력할 가치가 없을 정도로 충분히 분산되어 있습니다.

차트

편집 : 나는 주로 크롬에서 이것을했습니다. 파이어 폭스와 IE는 종종 데니스를 몇 % 선호합니다.


0

간단한 방법 :

String.prototype.repeat = function(num) {
    num = parseInt(num);
    if (num < 0) return '';
    return new Array(num + 1).join(this);
}

0

사람들은 이것을 엄청나게 복잡하게 만들거나 성능을 낭비합니다. 배열? 재귀? 당신은 나를 농담해야합니다.

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

편집하다. 나는 artistoex / disfated 및 다른 많은 사람들이 게시 한 비트 버전과 비교하기 위해 간단한 테스트를 실행했습니다. 후자는 조금 더 빠르지 만 메모리 효율성은 훨씬 뛰어납니다. 'blah'라는 단어가 1000000 회 반복되는 경우 노드 프로세스는 간단한 연결 알고리즘을 사용하여 최대 46MB까지 올라갔지 만 로그 알고리즘을 사용하면 5.5MB에 불과했습니다. 후자는 분명히 갈 길입니다. 명확성을 위해 다시 게시 :

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

string += string시간 의 중복 이 있습니다.
nikolay

0

숫자를 기준으로 문자열 연결

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));

희망이 도움이됩니다!


0

ES8을 사용하면 padStart또는 padEnd이것을 사용할 수도 있습니다 . 예.

var str = 'cat';
var num = 23;
var size = str.length * num;
"".padStart(size, str) // outputs: 'catcatcatcatcatcatcatcatcatcatcatcatcatcatcatcatcatcatcatcatcatcatcat'
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.