दोहराएँ स्ट्रिंग - जावास्क्रिप्ट


271

एक मनमाने ढंग से बार-बार एक स्ट्रिंग को लौटाने के लिए सबसे अच्छा या सबसे संक्षिप्त तरीका क्या है?

निम्नलिखित मेरा अब तक का सबसे अच्छा शॉट है:

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

5
10 साल पहले इस समस्या का एक जाना- पहचाना हल था, और जिसे मैंने जावास्क्रिप्ट ऑप्टिमाइज़ेशन आर्टिकल में एक उदाहरण के रूप में इस्तेमाल किया था, कुछ महीने पहले आपने यह सवाल पूछा था: webreference.com/programming/javascript/jkm3/3 .html जाहिरा तौर पर, ज्यादातर लोग उस कोड के बारे में भूल गए हैं, और मुझे नीचे दिए गए किसी भी समाधान को उतना अच्छा नहीं लगता जितना कि मेरा। सबसे अच्छा एल्गोरिथ्म ऐसा लगता है जैसे इसे मेरे कोड से हटा दिया गया था; मेरे कोड के काम करने की गलतफहमी के कारण, यह घातीय संघनन का एक अतिरिक्त चरण है जो एक विशेष लूप के साथ मेरे मूल में समाप्त हो गया है।
जोसेफ मायर्स

10
किसी ने यूसुफ का हल नहीं निकाला। एल्गोरिथ्म 3700 साल पुराना है। अतिरिक्त कदम की लागत नगण्य है। और इस लेख में जावास्क्रिप्ट में स्ट्रिंग संघनन के संबंध में त्रुटियां और गलत धारणाएं हैं। किसी के लिए भी कैसे जावास्क्रिप्ट वास्तव में आंतरिक रूप से तारों को संभालता है, रोप देखें ।
कलाकार

4
किसी ने नहीं देखा है कि स्ट्रिंग प्रोटॉयप रिपीट को परिभाषित और कार्यान्वित किया जाता है, कम से कम फ़ायरफ़ॉक्स में।
केनेबेक

3
@kennebec: हाँ, यह एक EcmaScript 6 फीचर है जो इस सवाल के पूछे जाने पर आसपास नहीं था। अब यह काफी अच्छी तरह से समर्थित है।
आरविन्ह

3
@rvighne - मैं तो बस अब जाँच kangax.github.io/compat-table/es6/#String.prototype.repeat मैं फ़ायरफ़ॉक्स से विशेष रूप से समर्थन और "के रूप में काफी अच्छी तरह से समर्थित" क्रोम पर विचार नहीं होगा
aaaaaa

जवाबों:


405

नए पाठकों पर ध्यान दें: यह उत्तर पुराना है और बहुत व्यावहारिक नहीं है - यह सिर्फ "चतुर" है क्योंकि यह स्ट्रिंग चीजों को प्राप्त करने के लिए एरे सामान का उपयोग करता है। जब मैंने "कम प्रक्रिया" लिखी, तो मेरा निश्चित रूप से "कम कोड" था, क्योंकि जैसा कि अन्य ने बाद के उत्तरों में नोट किया है, यह एक सुअर की तरह प्रदर्शन करता है। यदि गति आपके लिए मायने रखती है तो इसका उपयोग न करें।

मैं सीधे स्ट्रिंग ऑब्जेक्ट पर यह फ़ंक्शन डालूंगा। एक सरणी बनाने के बजाय, इसे भरना, और इसे एक खाली चार्ट के साथ जोड़ना, बस उचित लंबाई का एक सरणी बनाएं, और इसे अपने वांछित स्ट्रिंग के साथ जोड़ दें। समान परिणाम, कम प्रक्रिया!

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

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

36
मैं देशी वस्तुओं का विस्तार नहीं करने की कोशिश करता हूं, लेकिन अन्यथा यह एक सुंदर समाधान है। धन्यवाद!
ब्रैड

34
@ ब्रैड - क्यों नहीं? आप एक ऐसे फ़ंक्शन के साथ वैश्विक नाम स्थान को प्रदूषित करेंगे, जिसमें एक अच्छी तरह से परिभाषित घर (स्ट्रिंग ऑब्जेक्ट) है?
पीटर बैली

16
दरअसल, आपके दोनों तर्क वैश्विक नामस्थान पर भी लागू होते हैं। अगर मैं एक नाम स्थान का विस्तार करने और संभावित टकराव करने जा रहा हूं, तो मैं इसे 1) वैश्विक 2 में नहीं करना चाहता) एक में वह प्रासंगिक है और 3) रिफ्लेक्टर के लिए आसान है। इसका मतलब है कि इसे स्ट्रिंग प्रोटोटाइप में डालना, वैश्विक रूप से नहीं।
पीटर बेली

11
एक परिवर्तन जो मैं इस फंक्शन में करूँगा, वह होगा parseInt () को "num" के इर्द-गिर्द रखना, क्योंकि यदि आपके पास एक संख्यात्मक स्ट्रिंग है, तो आपको JS के प्रकार की बाजीगरी के कारण अजीब व्यवहार मिल सकता है। उदाहरण के लिए: "माई स्ट्रिंग" .repeat ("6") == "61"
निक नेम

19
यदि आप मूल वस्तुओं का विस्तार नहीं करना चाहते हैं, तो आप फ़ंक्शन को इसके बजाय स्ट्रिंग ऑब्जेक्ट पर रख सकते हैं 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;
}

यह आर्टिऑक्स एल्गोरिथम पर आधारित है। यह वास्तव में तेज है। और बड़ा count, पारंपरिक के साथ तुलना में यह तेजी से बढ़ता हैnew Array(count + 1).join(string) दृष्टिकोण के ।

मैंने केवल 2 चीजें बदली हैं:

  1. के pattern = thisसाथ बदल दियाpattern = this.valueOf() (एक स्पष्ट प्रकार रूपांतरण को साफ़ करता है);
  2. प्रोटोटाइपोटाइप्सif (count < 1) से जोड़ा गया चेकउस मामले में अनावश्यक क्रियाओं को बाहर करने के लिए को फ़ंक्शन के शीर्ष पर ।
  3. डेनिस जवाब से अनुकूलन लागू किया (5-7% गति)

युपीडी

रुचि रखने वालों के लिए यहां थोड़ा प्रदर्शन-परीक्षण का खेल का मैदान बनाया गया ।

चर count~ ० ।। १००:

प्रदर्शन आरेख

निरंतर count= 1024:

प्रदर्शन आरेख

अगर आप इसे इस्तेमाल कर सकते हैं और इसे और भी तेज़ बना सकते हैं :)


4
अच्छा काम! मुझे लगता है कि count < 1मामला वास्तव में अनावश्यक अनुकूलन है।
JayVee

उत्कृष्ट एल्गोरिथ्म ओ (लॉग एन)।
ValueOf

2
छवि लिंक मर चुके हैं।
बेंजामिन ग्रुएनबाम

लिंक ठीक हैं। अस्थायी रूप से अनुपलब्धता हो सकती है
विघटित

परीक्षण JSFiddle किसी भी अधिक सही ढंग से काम नहीं करता है; ऐसा लगता है कि बस पहले फंक्शन को बार-बार चलाते रहना चाहिए (इसे आधे घंटे तक चलने के लिए छोड़ दिया जाए)
रेवनप्रोडिगलक्नाइट

47

यह समस्या जावास्क्रिप्ट के लिए एक प्रसिद्ध / "क्लासिक" अनुकूलन मुद्दा है, इस तथ्य के कारण कि जावास्क्रिप्ट तार "अपरिवर्तनीय" हैं और इसके अलावा एक स्ट्रिंग के लिए एक भी वर्ण के संघनन के लिए स्मृति आवंटन सहित और प्रतिलिपि बनाने के लिए आवश्यक है। , एक पूरी नई स्ट्रिंग।

दुर्भाग्य से, इस पृष्ठ पर स्वीकृत उत्तर गलत है, जहां "गलत" का अर्थ है साधारण एक-वर्ण स्ट्रिंग्स के लिए 3x का एक प्रदर्शन कारक, और छोटे तारों के लिए 8x-97x अधिक बार दोहराया गया, दोहराए जाने वाले वाक्यों के लिए 300x, और असीम रूप से। एल्गोरिदम की जटिलता के अनुपात की सीमा nको अनंत तक ले जाना। साथ ही, इस पृष्ठ पर एक और उत्तर है जो लगभग सही है (पिछले 13 वर्षों में इंटरनेट पर घूमने वाले सही समाधान की कई पीढ़ियों और विविधताओं में से एक पर आधारित है)। हालांकि, यह "लगभग सही" समाधान सही एल्गोरिथ्म के एक महत्वपूर्ण बिंदु को याद करता है, जिससे 50% प्रदर्शन में गिरावट होती है।

जेएस प्रदर्शन परिणाम स्वीकार किए गए उत्तर के लिए, शीर्ष-प्रदर्शन वाले अन्य उत्तर (इस उत्तर में मूल एल्गोरिथ्म के अपमानित संस्करण के आधार पर), और यह उत्तर मेरे एल्गोरिथ्म का उपयोग करके 13 साल पहले बनाया गया था

~ अक्टूबर 2000 मैंने इस सटीक समस्या के लिए एक एल्गोरिथ्म प्रकाशित किया था जिसे व्यापक रूप से अनुकूलित, संशोधित किया गया था, फिर अंततः खराब समझा और भुला दिया गया। इस समस्या को दूर करने के लिए, अगस्त 2008 में, मैंने एक लेख प्रकाशित किया था http://www.webreference.com/programming/javascript/jkm3/3.html एल्गोरिथम को समझाते हुए और इसे सामान्य-प्रयोजन जावास्क्रिप्ट अनुकूलन के सरल के उदाहरण के रूप में उपयोग करते हुए। अब तक, वेब संदर्भ ने इस लेख से मेरी संपर्क जानकारी और यहां तक ​​कि मेरा नाम भी साफ़ कर दिया है। और एक बार फिर, एल्गोरिथ्म को व्यापक रूप से अनुकूलित किया गया है, संशोधित किया गया है, फिर खराब रूप से समझा गया है और काफी हद तक भुला दिया गया है।

जोसेफ मायर्स द्वारा मूल स्ट्रिंग पुनरावृत्ति / गुणन जावास्क्रिप्ट एल्गोरिथ्म, पाठ Y.Ks के रूप में एक पाठ गुणन फ़ंक्शन के रूप में Y2K; वेब संदर्भ द्वारा इस रूप में अगस्त, 2008 को प्रकाशित: http://www.webreference.com/programming/javascript/jkm3/3.html (लेख में जावास्क्रिप्ट अनुकूलन के उदाहरण के रूप में फ़ंक्शन का उपयोग किया गया है, जो केवल अजीब के लिए है नाम "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;
}

उस लेख के प्रकाशन के दो महीने के भीतर, यह एक ही सवाल स्टैक ओवरफ्लो में पोस्ट किया गया था और अब तक मेरे रडार के नीचे उड़ गया था, जब जाहिर तौर पर इस समस्या के लिए मूल एल्गोरिथ्म को एक बार फिर से भुला दिया गया था। इस स्टैक ओवरफ्लो पेज पर उपलब्ध सबसे अच्छा समाधान मेरे समाधान का एक संशोधित संस्करण है, संभवतः कई पीढ़ियों द्वारा अलग किया गया है। दुर्भाग्य से, संशोधनों ने समाधान की इष्टतमता को बर्बाद कर दिया। वास्तव में, मेरे मूल से लूप की संरचना को बदलकर, संशोधित समाधान घातीय डुप्लिकेटिंग का एक पूरी तरह से अनावश्यक अतिरिक्त चरण निष्पादित करता है (इस प्रकार एक अतिरिक्त समय के साथ उचित उत्तर में उपयोग किए जाने वाले सबसे बड़े स्ट्रिंग में शामिल होता है और फिर इसे त्याग देता है)।

नीचे इस समस्या के सभी उत्तर और सभी के लाभ से संबंधित कुछ जावास्क्रिप्ट अनुकूलन की चर्चा शामिल है।

तकनीक: वस्तुओं या वस्तु गुणों के संदर्भ से बचें

यह समझने के लिए कि यह तकनीक कैसे काम करती है, हम एक वास्तविक जीवन जावास्क्रिप्ट फ़ंक्शन का उपयोग करते हैं जो कि जिस भी लंबाई की आवश्यकता होती है उसके तार बनाता है। और जैसा कि हम देखेंगे, अधिक अनुकूलन जोड़े जा सकते हैं!

यहां उपयोग किया जाने वाला एक फ़ंक्शन पैसे के प्रारूपण के लिए, या सीमा तक ब्लॉक डेटा को भरने के लिए पाठ के संरेखित कॉलम के लिए पैडिंग बनाना है। एक पाठ पीढ़ी फ़ंक्शन पाठ पर संचालित किसी भी अन्य फ़ंक्शन के परीक्षण के लिए चर लंबाई इनपुट की अनुमति देता है। यह फ़ंक्शन जावास्क्रिप्ट टेक्स्ट प्रोसेसिंग मॉड्यूल के महत्वपूर्ण घटकों में से एक है।

जैसा कि हम आगे बढ़ते हैं, हम स्ट्रिंग्स बनाने के लिए एक अनुकूलित एल्गोरिथ्म में मूल कोड को विकसित करते हुए दो सबसे महत्वपूर्ण अनुकूलन तकनीकों को कवर करेंगे। अंतिम परिणाम एक औद्योगिक-शक्ति, उच्च-प्रदर्शन फ़ंक्शन है जिसका मैंने हर जगह उपयोग किया है - आइटम की कीमतें और जावास्क्रिप्ट को ऑर्डर ऑर्डर, डेटा स्वरूपण और ईमेल / पाठ संदेश स्वरूपण और कई अन्य उपयोगों में संरेखित करना।

तार बनाने के लिए मूल कोड stringFill1()

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

वाक्य रचना यहाँ स्पष्ट है। जैसा कि आप देख सकते हैं, हमने अधिक अनुकूलन के लिए जाने से पहले पहले ही स्थानीय फ़ंक्शन चर का उपयोग किया है।

ध्यान रखें कि एक वस्तु संपत्ति का एक निर्दोष संदर्भ है s.length कोड में उसके प्रदर्शन को नुकसान पहुंचाता है। इससे भी बदतर, इस ऑब्जेक्ट प्रॉपर्टी के उपयोग से प्रोग्राम की सरलता को यह अनुमान लगाकर कम कर दिया जाता है कि पाठक जावास्क्रिप्ट स्ट्रिंग ऑब्जेक्ट्स के गुणों के बारे में जानता है।

इस ऑब्जेक्ट प्रॉपर्टी के उपयोग से कंप्यूटर प्रोग्राम की व्यापकता नष्ट हो जाती है। कार्यक्रम मानता है कि xलंबाई की एक स्ट्रिंग होनी चाहिए। यह stringFill1()एकल वर्णों की पुनरावृत्ति को छोड़कर फ़ंक्शन के अनुप्रयोग को कुछ भी सीमित करता है । यहां तक ​​कि एकल वर्णों का उपयोग नहीं किया जा सकता है यदि उनमें HTML इकाई की तरह कई बाइट्स हों &nbsp;

किसी ऑब्जेक्ट प्रॉपर्टी के इस अनावश्यक उपयोग के कारण सबसे खराब समस्या यह है कि फ़ंक्शन एक अनन्त लूप बनाता है यदि रिक्त इनपुट स्ट्रिंग पर परीक्षण किया जाता है x । सामान्यता की जांच करने के लिए, छोटी से छोटी संभव इनपुट के लिए एक कार्यक्रम लागू करें। एक प्रोग्राम जो उपलब्ध मेमोरी की मात्रा से अधिक होने पर क्रैश करता है, उसका एक बहाना है। इस तरह का एक कार्यक्रम जो कुछ भी नहीं बनाने के लिए कहा जाता है, वह अस्वीकार्य है। कभी-कभी सुंदर कोड जहरीला कोड होता है।

सादगी कंप्यूटर प्रोग्रामिंग का एक अस्पष्ट लक्ष्य हो सकता है, लेकिन आम तौर पर यह नहीं है। जब किसी कार्यक्रम में सामान्यता का कोई उचित स्तर नहीं होता है, तो यह कहना मान्य नहीं है, "यह कार्यक्रम जितना अच्छा है उतना ही अच्छा है।" जैसा कि आप देख सकते हैं, string.lengthसंपत्ति का उपयोग इस कार्यक्रम को सामान्य सेटिंग में काम करने से रोकता है, और वास्तव में, गलत प्रोग्राम ब्राउज़र या सिस्टम क्रैश का कारण बनने के लिए तैयार है।

क्या इस जावास्क्रिप्ट के प्रदर्शन को सुधारने के साथ-साथ इन दो गंभीर समस्याओं का भी ध्यान रखना है?

बेशक। बस पूर्णांक का उपयोग करें।

तार बनाने के लिए अनुकूलित कोड 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 माइक्रोसेकंड (सेकंड का मिलियन) stringFill2()लेता है , और यही काम करने के लिए 27.68 माइक्रोसेकंड लेता है। यह एक वस्तु संपत्ति के संदर्भ से बचकर प्रदर्शन में लगभग दोगुना है।

तकनीक: छोटे तार को लंबे तारों से जोड़ने से बचें

हमारा पिछला परिणाम अच्छा लगा - बहुत अच्छा, वास्तव में। stringFill2()हमारे पहले दो अनुकूलन के उपयोग के कारण बेहतर कार्य बहुत तेजी से होता है। क्या आप इस पर विश्वास करेंगे अगर मैंने आपसे कहा कि यह अब की तुलना में कई गुना तेज हो सकता है?

हां, हम उस लक्ष्य को पूरा कर सकते हैं। अभी हमें यह समझाने की आवश्यकता है कि हम छोटे तारों को लंबे तारों से जोड़ने से कैसे बचें।

हमारे मूल कार्य की तुलना में अल्पकालिक व्यवहार काफी अच्छा प्रतीत होता है। कंप्यूटर वैज्ञानिक किसी फ़ंक्शन या कंप्यूटर प्रोग्राम एल्गोरिथ्म के "असममित व्यवहार" का विश्लेषण करना पसंद करते हैं, जिसका अर्थ है कि बड़े इनपुट के साथ परीक्षण करके इसके दीर्घकालिक व्यवहार का अध्ययन करना। कभी-कभी और परीक्षण किए बिना, कभी भी उन तरीकों के बारे में पता नहीं चलता है जिनसे कंप्यूटर प्रोग्राम को बेहतर बनाया जा सकता है। क्या होगा देखने के लिए, हम एक 200-बाइट स्ट्रिंग बनाने जा रहे हैं।

जो समस्या दिखती है stringFill2()

हमारे टाइमिंग फ़ंक्शन का उपयोग करते हुए, हम पाते हैं कि 200-बाइट स्ट्रिंग के लिए समय 62.54 माइक्रोसेकंड तक बढ़ जाता है, जबकि 100-बाइट स्ट्रिंग के लिए 27.68 है। ऐसा लगता है कि समय को दोगुना करने के लिए दोगुना काम करना चाहिए, लेकिन इसके बजाय यह तिगुना या चौगुना है। प्रोग्रामिंग अनुभव से, यह परिणाम अजीब लगता है, क्योंकि यदि कुछ भी हो, तो फ़ंक्शन को थोड़ा तेज़ी से होना चाहिए क्योंकि कार्य अधिक कुशलता से किया जा रहा है (फ़ंक्शन फ़ंक्शन प्रति कॉल 200 बाइट्स के बजाय 200 बाइट्स)। इस मुद्दे को जावास्क्रिप्ट स्ट्रिंग्स की एक कपटी संपत्ति के साथ करना है: जावास्क्रिप्ट स्ट्रिंग्स "अपरिवर्तनीय हैं।"

अपरिवर्तनीय का अर्थ है कि आपके द्वारा बनाया जाने के बाद आप एक स्ट्रिंग नहीं बदल सकते। एक बार में एक बाइट को जोड़कर, हम प्रयास के एक और बाइट का उपयोग नहीं कर रहे हैं। हम वास्तव में पूरे स्ट्रिंग प्लस एक और बाइट को फिर से बना रहे हैं।

वास्तव में, 100 बाइट स्ट्रिंग में एक और बाइट जोड़ने के लिए, यह 101 बाइट्स के लायक काम करता है। आइए Nबाइट्स की एक स्ट्रिंग बनाने के लिए कम्प्यूटेशनल लागत का संक्षेप में विश्लेषण करें । पहली बाइट को जोड़ने की लागत कम्प्यूटेशनल प्रयास की 1 इकाई है। दूसरी बाइट को जोड़ने की लागत एक इकाई नहीं है, बल्कि 2 इकाइयाँ हैं (पहली बाइट की नकल एक नई स्ट्रिंग ऑब्जेक्ट के साथ-साथ दूसरी बाइट को जोड़ने के लिए)। तीसरे बाइट के लिए 3 यूनिट आदि की लागत की आवश्यकता होती है।

C(N) = 1 + 2 + 3 + ... + N = N(N+1)/2 = O(N^2)। प्रतीक O(N^2)को एन स्क्वेर्ड का बिग ओ कहा जाता है, और इसका मतलब है कि लंबे समय में कम्प्यूटेशनल लागत स्ट्रिंग लंबाई के वर्ग के लिए आनुपातिक है। १०० अक्षर बनाने के लिए १०,००० यूनिट काम लेता है, और २०० कैरेक्टर बनाने में ४०,००० यूनिट काम लगता है।

यही कारण है कि 100 वर्णों से 200 वर्ण बनाने में दो बार से अधिक समय लगा। वास्तव में, इसे लंबे समय तक चार बार लेना चाहिए था। हमारा प्रोग्रामिंग अनुभव सही था कि काम को लंबे समय तक तार के लिए थोड़ा और अधिक कुशलता से किया जा रहा है, और इसलिए इसे केवल तीन बार लंबे समय तक लिया गया। एक बार जब फंक्शन कॉल का ओवरहेड नगण्य हो जाता है, तो हम कितनी देर तक एक स्ट्रिंग बना रहे हैं, यह वास्तव में एक स्ट्रिंग को दो बार लंबे समय तक बनाने में चार गुना अधिक समय लेगा।

(ऐतिहासिक नोट: यह विश्लेषण आवश्यक रूप से स्रोत कोड में स्ट्रिंग पर लागू नहीं होता है, जैसे कि html = 'abcd\n' + 'efgh\n' + ... + 'xyz.\n', जावास्क्रिप्ट स्रोत कोड कंपाइलर स्ट्रिंग स्ट्रिंग ऑब्जेक्ट में बनाने से पहले एक साथ जुड़ सकते हैं। कुछ साल पहले, KJS कार्यान्वयन। स्रोत कोड के लंबे तारों को लोड करने पर प्लस संकेतों द्वारा जावास्क्रिप्ट को फ्रीज या क्रैश किया जाएगा। चूंकि कम्प्यूटेशनल समय था, O(N^2)इसलिए वेब पेज बनाना मुश्किल नहीं था, जो कोनकेर वेब ब्राउज़र या सफारी को अधिभारित करता था, जिसमें केजेएस जावास्क्रिप्ट इंजन कोर का उपयोग किया जाता था। जब मैं एक मार्कअप भाषा और जावास्क्रिप्ट मार्कअप भाषा पार्सर विकसित कर रहा था तब इस मुद्दे पर आया था, और तब मुझे पता चला कि जब मैंने जावास्क्रिप्ट के लिए अपनी स्क्रिप्ट लिखी थी तो क्या समस्या थी।)

स्पष्ट रूप से प्रदर्शन का यह तीव्र क्षरण एक बहुत बड़ी समस्या है। हम इसे कैसे निपटा सकते हैं, यह देखते हुए कि हम जावास्क्रिप्ट को अपरिवर्तनीय वस्तुओं के रूप में संभालने के तरीके को नहीं बदल सकते हैं? समाधान एक एल्गोरिथ्म का उपयोग करना है जो स्ट्रिंग को जितनी बार संभव हो उतना फिर से बनाता है।

स्पष्ट करने के लिए, हमारा लक्ष्य छोटे तारों को लंबे तारों से जोड़ने से बचना है, क्योंकि छोटी स्ट्रिंग को जोड़ने के लिए, पूरे लंबे स्ट्रिंग को भी डुप्लिकेट करना होगा।

एल्गोरिथ्म लंबे स्ट्रिंग्स में छोटे तारों को जोड़ने से बचने के लिए कैसे काम करता है

यहां नई स्ट्रिंग ऑब्जेक्ट्स की संख्या को कम करने का एक अच्छा तरीका है। लंबे समय तक एक साथ स्ट्रिंग की लंबाई को मिलाएं ताकि एक बार में एक से अधिक बाइट आउटपुट में जुड़ जाए।

उदाहरण के लिए, लंबाई की एक स्ट्रिंग बनाने के लिए 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 की एक स्ट्रिंग, फिर लंबाई की एक स्ट्रिंग 4 लंबाई 4 की एक स्ट्रिंग, फिर लंबाई 1 की लंबाई प्राप्त करने के लिए लंबाई 1 से स्ट्रिंग 1 की लंबाई 8। हम जो कर रहे हैं, उसे संक्षेप में लंबी स्ट्रिंग या छोटे तार जोड़ने से बचा जा सकता है। शब्द, समान या लगभग समान लंबाई वाले तार को एक साथ जोड़ने की कोशिश करना।

पुरानी कम्प्यूटेशनल लागत के लिए हमें एक सूत्र मिला N(N+1)/2। क्या नई लागत के लिए कोई फॉर्मूला है? हां, लेकिन यह जटिल है। महत्वपूर्ण बात यह है कि यह है O(N), और इसलिए स्ट्रिंग की लंबाई को दोगुना करना लगभग चौगुना करने के बजाय काम की मात्रा को दोगुना कर देगा।

इस नए विचार को लागू करने वाला कोड कम्प्यूटेशनल लागत के सूत्र के रूप में लगभग जटिल है। जब आप इसे पढ़ते हैं, तो याद रखें कि >>= 11 बाइट द्वारा दाईं ओर शिफ्ट करने का मतलब है। तो अगर n = 10011एक बाइनरी नंबर है, तो n >>= 1मूल्य में परिणाम होता है n = 1001

कोड का दूसरा हिस्सा जिसे आप नहीं पहचान सकते हैं, वह बिटवाइज़ और ऑपरेटर है, जिसे लिखा गया है &n & 1यदि अंतिम बाइनरी अंक n1 है, और यदि n0 का अंतिम बाइनरी अंक है, तो यह अभिव्यक्ति सही है।

नया अत्यधिक कुशल 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 माइक्रोसेकंड (सेकंड का मिलियन) stringFill2()लेता है, 62.54 लेता है, और stringFill3()केवल 4.608 लेता है। क्या इस एल्गोरिथ्म इतना बेहतर बना दिया? सभी फ़ंक्शन ने स्थानीय फ़ंक्शन चर का उपयोग करने का लाभ उठाया, लेकिन दूसरे और तीसरे अनुकूलन तकनीकों का लाभ उठाते हुए प्रदर्शन में बीस गुना सुधार किया stringFill3()

गहरा विश्लेषण

क्या यह विशेष कार्य पानी से प्रतियोगिता को उड़ा देता है?

जैसा कि मैंने उल्लेख किया है, कारण है कि इन दोनों कार्यों, stringFill1()औरstringFill2() , इतनी धीमी गति से चलाना कि जावास्क्रिप्ट तार अपरिवर्तनीय हैं। जावास्क्रिप्ट द्वारा संचित स्ट्रिंग डेटा में एक बार में एक और बाइट की अनुमति देने के लिए मेमोरी को फिर से विभाजित नहीं किया जा सकता है। हर बार एक और बाइट को स्ट्रिंग के अंत में जोड़ा जाता है, पूरे स्ट्रिंग को शुरुआत से अंत तक पुनर्जीवित किया जाता है।

इस प्रकार, स्क्रिप्ट के प्रदर्शन को बेहतर बनाने के लिए, किसी को समय से पहले एक साथ दो तारों को समतल करके लंबे समय तक तार को लंबा करना चाहिए, और फिर पुन: वांछित स्ट्रिंग लंबाई का निर्माण करना चाहिए।

उदाहरण के लिए, 16-अक्षर बाइट स्ट्रिंग बनाने के लिए, पहले एक दो बाइट स्ट्रिंग को प्री-कॉम्पट्यूट किया जाएगा। फिर दो बाइट स्ट्रिंग को एक चार-बाइट स्ट्रिंग को पूर्ववर्ती करने के लिए पुन: उपयोग किया जाएगा। फिर चार-बाइट स्ट्रिंग को आठ बाइट स्ट्रिंग को पूर्ववर्ती करने के लिए पुन: उपयोग किया जाएगा। अंत में, 16 बाइट्स की वांछित नई स्ट्रिंग बनाने के लिए दो आठ-बाइट स्ट्रिंग्स का पुन: उपयोग किया जाएगा। कुल मिलाकर चार नए तार बनाए जाने थे, लंबाई 2 में से एक, लंबाई 4 में से एक, लंबाई 8 में से एक और लंबाई 16 में से एक। कुल लागत 2 + 4 + 8 + 16 = 30 है।

लंबे समय में इस दक्षता की गणना रिवर्स ऑर्डर में जोड़कर की जा सकती है और पहले टर्म a1 = N से शुरू होने वाली और ज्यामिति श्रृंखला का उपयोग करके r = 1/2 का सामान्य अनुपात होता है। एक ज्यामितीय श्रृंखला का योग द्वारा दिया जाता है a_1 / (1-r) = 2N

यह लंबाई 2 की एक नई स्ट्रिंग बनाने के लिए एक चरित्र को जोड़ने से अधिक कुशल है, लंबाई 3, 4, 5 की एक नई स्ट्रिंग का निर्माण, और इसी तरह 16 तक। पिछले एल्गोरिथ्म ने एक बार में एक ही बाइट जोड़ने की उस प्रक्रिया का उपयोग किया। , और इसकी कुल लागत होगी 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 सेकंड में बनाता है।

मैं स्टैक ओवरफ्लो पर एक कैनोनिकल जवाब के रूप में लेख के हिस्से को पुन: पेश करने के लिए समय लेना चाहता हूं।

ध्यान दें कि यहां सबसे अच्छा प्रदर्शन करने वाला एल्गोरिथ्म स्पष्ट रूप से मेरे एल्गोरिथ्म पर आधारित है और संभवतः किसी और की तीसरी या चौथी पीढ़ी के अनुकूलन से विरासत में मिला था। दुर्भाग्य से, संशोधनों के परिणामस्वरूप इसके प्रदर्शन को कम किया गया। यहाँ प्रस्तुत मेरे समाधान की भिन्नता ने शायद मेरी भ्रमित for (;;)अभिव्यक्ति को नहीं समझा , जो सी में लिखे सर्वर के मुख्य अनंत लूप की तरह दिखता है, और जिसे केवल लूप नियंत्रण के लिए सावधानी से तैनात ब्रेक स्टेटमेंट की अनुमति देने के लिए डिज़ाइन किया गया था, सबसे कॉम्पैक्ट तरीका तेजी से एक अतिरिक्त अनावश्यक समय की नकल करने से बचें।


4
इस उत्तर को कई उत्थान नहीं मिले। सबसे पहले, जोसेफ के स्वामित्व के दावे हास्यास्पद हैं। अंतर्निहित एल्गोरिथ्म 3700 साल पुराना है।
कलाकार

2
दूसरा, इसमें बहुत सारी गलत सूचनाएँ हैं। आधुनिक जावास्क्रिप्ट कार्यान्वयन भी एक स्ट्रिंग की सामग्री को स्पर्श नहीं करते हैं जब समवशरण प्रदर्शन (v8 प्रकार की वस्तु के रूप में संक्षिप्त स्ट्रिंग का प्रतिनिधित्व करता है)। शेष सभी संवर्द्धन नगण्य हैं (असममित जटिलता के संदर्भ में)।
कलाकार

3
तार कैसे समाप्‍त किए जाते हैं, इसका आपका विचार गलत है। दो तारों को समेटने के लिए, जावास्क्रिप्ट घटक के तारों के बाइट को बिल्कुल नहीं पढ़ता है। इसके बजाय, यह केवल एक ऑब्जेक्ट बनाता है जो बाएं और दाएं हिस्से को संदर्भित करता है। यही कारण है कि लूप में अंतिम कॉन्टैनेशन पहले वाले की तुलना में अधिक महंगा नहीं है।
कलाकार

3
बेशक, यह स्ट्रिंग को अनुक्रमित करने के लिए ओ (1) लागत की तुलना में बड़ा है, इसलिए समवर्ती को बाद में बाहर समतल किया जा सकता है जो वास्तव में आगे के मूल्यांकन का गुण रखता है।
कलाकार

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
@ दोस्तों, मुझे लगता है कि मतदान का विचार किसी व्यक्ति के लिए या किसी व्यक्ति की रचनात्मकता के लिए मतदान से कम है (जो वास्तव में प्रशंसनीय है), लेकिन विचार सबसे पूर्ण समाधान के लिए मतदान करना है, ताकि इसे आसानी से पाया जा सके। सूची के शीर्ष, सही एक के लिए खोज में सभी उत्तरों को पढ़ने के बिना। (क्योंकि, दुर्भाग्य से, हम सभी के पास सीमित समय है ...)
सोरिन पोस्टेलनिकु

38

खुशखबरी! String.prototype.repeatहै अब JavaScript का एक हिस्सा

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

इंटरनेट एक्सप्लोरर और एंड्रॉइड वेबव्यू को छोड़कर, विधि सभी प्रमुख ब्राउज़रों द्वारा समर्थित है। अद्यतित सूची के लिए, MDN: String.prototype.repeat> ब्राउज़र संगतता देखें

एमडीएन में बिना समर्थन के ब्राउज़रों के लिए एक पॉलीफिल है


धन्यवाद मामलों की वर्तमान स्थिति पर धन्यवाद, हालांकि मुझे लगता है कि मोज़िला पॉलीफ़िल अधिकांश आवश्यकताओं के लिए जटिल है (मुझे लगता है कि वे अपने कुशल सी कार्यान्वयन के व्यवहार की नकल करने की कोशिश करते हैं) - इसलिए वास्तव में संक्षिप्तता के लिए ओपी की आवश्यकता का जवाब नहीं देगा। पॉलीफ़िल के रूप में स्थापित किए गए अन्य तरीकों में से कोई भी अधिक संक्षिप्त होने के लिए बाध्य है
;;

2
निश्चित रूप से! लेकिन बिल्ट-इन का उपयोग करना सबसे संक्षिप्त संस्करण होना चाहिए। चूंकि पॉलीफिल मूल रूप से सिर्फ बैक-पोर्ट होते हैं, इसलिए वे ऐनक (या प्रस्तावित चश्मा, इस मामले में) के साथ संगतता सुनिश्चित करने के लिए थोड़ा जटिल होते हैं। मैंने इसे पूर्णता के लिए जोड़ा, यह ओपी पर निर्भर है कि किस विधि का उपयोग करना है, मुझे लगता है।
एंड्रे लास्ज़लो

19

String.prototype.repeat अब ES6 Standard है।

'abc'.repeat(3); //abcabcabc

अच्छा! .. लेकिन मेरे लिए उपयोग करने योग्य नहीं (यह ios पर समर्थित नहीं है <9): kangax.github.io/compat-table/es6
बेंजामिन

@Benjamin लिंक पर पॉलीफ़िल का उपयोग करें।
लुईस

मुझे लगता है कि एक चुटकी भरा जवाब होना चाहिए ।
टेस्ट 30

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);}
जूल

वैसे भी इस परीक्षण के अनुसार ( jsperf.com/string-repeat/2 ) स्ट्रिंग समवर्ती के साथ लूप के लिए एक सरल कार्य करना Array.join का उपयोग करने की तुलना में क्रोम पर तेज़ तरीके से प्रतीत होता है। यह अजीब नहीं है ?!
मार्को डेमायो


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

यह है कि डेलमीटर का उपयोग करके कई बार स्ट्रिंग को कैसे दोहराया जाए।


4

यहाँ विच्छेदित उत्तर पर 5-7% सुधार हुआ है।

लूप को रोक कर अनियंत्रित करें और लूप के बाद count > 1एक अतिरिक्त result += pattnernकंसट्रेट करें। यह pattern += patternएक महंगे इफ-चेक का उपयोग किए बिना पहले से अप्रयुक्त लूप्स से बच जाएगा । अंतिम परिणाम इस तरह दिखेगा:

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

और यहाँ अनियंत्रित संस्करण के लिए फोलेटेड फिडेल कांटा गया है: http://jsfiddle.net/wsdfg/


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

2
क्या स्ट्रिंग संघनन महंगा नहीं है? यह जावा में कम से कम मामला है।
विजय देव

वे क्यों हाँ? हालाँकि, यह वास्तव में जावास्क्रिप्ट में अनुकूलित नहीं किया जा सकता है। :(
McTrafik

इस प्रदर्शन के बारे में क्या अनुचित है: var r=s; for (var a=1;...:)))) इस परीक्षण ( jsperf.com/string-repeat/2 ) के अनुसार वैसे भी लूप के लिए एक स्ट्रिंग के साथ एक सरल कार्य करना जैसे कि आपने जो सुझाव दिया है वह क्रोम का उपयोग करने की तुलना में क्रोम पर तेज़ लगता है .join।
मार्को डेमायो

@ वीजयदेव - इस परीक्षण के अनुसार नहीं: 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(''); }

यदि आप दोनों विकल्पों के प्रदर्शन की तुलना करना चाहते हैं, तो इस फिडल और इस फिडेल को देखें बेंचमार्क परीक्षणों के लिए को देखें। मेरे अपने परीक्षणों के दौरान, दूसरा विकल्प फ़ायरफ़ॉक्स में लगभग 2 गुना तेज और क्रोम में लगभग 4 गुना तेज था!

केवल आधुनिक ब्राउज़र के लिए:

आधुनिक ब्राउज़रों में, अब आप यह भी कर सकते हैं:

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

यह विकल्प न केवल अन्य विकल्पों की तुलना में कम है, बल्कि यह दूसरे विकल्प से भी तेज है।

दुर्भाग्य से, यह इंटरनेट एक्सप्लोरर के किसी भी संस्करण में काम नहीं करता है। तालिका के नंबर पहले ब्राउज़र संस्करण को निर्दिष्ट करते हैं जो पूरी तरह से विधि का समर्थन करता है:

यहां छवि विवरण दर्ज करें


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

आप इसे JSFiddle पर परीक्षण कर सकते हैं । हैकी Array.joinऔर मेरा के खिलाफ बेंचमार्क है, मोटे तौर पर (क्रोम पर) 100 (सफारी) से 200 (फ़ायरफ़ॉक्स) गुना (ब्राउज़र पर निर्भर करता है)।


2

बस एक और दोहराव समारोह:

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

2

ES2015इस 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/ स्ट्रिंग / दोहराएं
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

सरल पुनरावर्ती संघनन

मैं बस इसे दंश देना चाहता था, और इसे बनाया:

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

इसलिये , गैर पुनरावर्ती विधि कॉल स्टैक सीमा से टकराने के बिना मनमाने ढंग से बड़े दोहराव को संभाल लेगी, यह बहुत धीमी है।

मैंने और विधियाँ जोड़ने की जहमत क्यों उठाई जो आधी होशियार नहीं हैं पहले से ही पोस्ट किए गए ?

आंशिक रूप से अपने स्वयं के मनोरंजन के लिए, और आंशिक रूप से सबसे सरल तरीके से इंगित करने के लिए मैं जानता हूं कि एक बिल्ली को त्वचा देने के कई तरीके हैं, और स्थिति के आधार पर, यह काफी संभव है कि जाहिरा तौर पर सबसे अच्छा तरीका आदर्श नहीं है।

एक अपेक्षाकृत तेज़ और परिष्कृत विधि कुछ परिस्थितियों में प्रभावी रूप से दुर्घटनाग्रस्त हो सकती है और जल सकती है, जबकि धीमी, सरल विधि से काम हो सकता है - अंततः।

कुछ तरीकों हो सकता है थोड़ा और अधिक शोषण से, और के रूप में ऐसी प्रवण करने के लिए किया जा रहा तय अस्तित्व से बाहर है, और अन्य तरीकों सभी शर्तों में खूबसूरती से काम कर सकते हैं, लेकिन इतना है कि निर्माण कर रहे हैं एक बस पता नहीं यह कैसे काम करता है।

"तो क्या हुआ अगर मुझे पता है कि यह कैसे काम करता है ?!"

गंभीरता से?

जावास्क्रिप्ट अपनी सबसे बड़ी ताकत से ग्रस्त है; यह बुरे व्यवहार के प्रति अत्यधिक सहिष्णु है, और इतना लचीला कि यह परिणाम वापस करने के लिए पीछे की तरफ झुक जाएगा, जब यह हर किसी के लिए बेहतर होता अगर यह तड़क जाता!

"महान शक्ति के साथ महान जिम्मेदारी आती है" ;-)

लेकिन अधिक गंभीरता से और महत्वपूर्ण रूप से, हालांकि इस तरह के सामान्य प्रश्न चतुर उत्तरों के रूप में अजीबता का कारण बनते हैं कि यदि और कुछ नहीं, तो किसी के ज्ञान और क्षितिज का विस्तार करें, अंत में, कार्य हाथ में - व्यावहारिक स्क्रिप्ट जो परिणामस्वरूप विधि का उपयोग करता है - सुझाव दिया जाता है की तुलना में थोड़ा कम, या थोड़ा अधिक चतुर की आवश्यकता हो सकती है ।

ये "सही" एल्गोरिदम मज़ेदार और सभी हैं, लेकिन "एक आकार सभी फिट बैठता है" शायद ही कभी होगा अगर कभी दर्जी से बेहतर हो।

यह उपदेश आपके लिए नींद की कमी और एक उत्तीर्ण रुचि के सौजन्य से लाया गया था। आगे बढ़ो और कोड!


1

सबसे पहले, ओपी के प्रश्न संक्षिप्तता के बारे में प्रतीत होते हैं - जिसे मैं "सरल और पढ़ने में आसान" समझता हूं, जबकि अधिकांश उत्तर दक्षता के बारे में प्रतीत होते हैं - जो स्पष्ट रूप से एक ही बात नहीं है और मुझे भी लगता है कि जब तक आप कुछ को लागू नहीं करते हैं विशिष्ट बड़े डेटा हेरफेर एल्गोरिदम, जब आप बुनियादी डेटा हेरफेर जावास्क्रिप्ट कार्यों को लागू करने के लिए आते हैं तो आपको चिंता नहीं करनी चाहिए। चिंता बहुत अधिक महत्वपूर्ण है।

दूसरे, जैसा कि एंड्रे लेस्ज़लो ने उल्लेख किया है, String.repeat ECMAScript 6 का हिस्सा है और पहले से ही कई लोकप्रिय कार्यान्वयन में उपलब्ध है - इसलिए इसे लागू करने के लिए सबसे संक्षिप्त कार्यान्वयन String.repeatनहीं है;;

अंत में, यदि आपको उन मेजबानों का समर्थन करने की आवश्यकता है जो ईसीएमएस्क्रिप्ट 6 कार्यान्वयन की पेशकश नहीं करते हैं, तो एमडीएन के पॉलीफिल का उल्लेख एंड्रे लेस्ज़लो द्वारा किया गया है, लेकिन कुछ भी नहीं है।

तो, आगे की हलचल के बिना - यहाँ मेरा संक्षिप्त पॉलीफ़िल है:

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

हाँ, यह एक पुनरावृत्ति है। मुझे पुनरावृत्तियाँ पसंद हैं - वे सरल हैं और यदि सही ढंग से किए गए हैं तो समझना आसान है। दक्षता के बारे में, अगर भाषा इसका समर्थन करती है तो वे सही ढंग से लिखे जाने पर बहुत कुशल हो सकते हैं।

मेरे परीक्षणों से, यह तरीका Array.joinदृष्टिकोण से ~ 60% अधिक तेज है । हालांकि यह स्पष्ट रूप से आता है कि कहीं न कहीं विघटित क्रियान्वयन करीब है, यह दोनों की तुलना में बहुत सरल है।

"स्ट्रिक्ट मोड" का उपयोग करके मेरा परीक्षण सेटअप नोड v0.10 है (मुझे लगता है कि यह कुछ प्रकार के TCO को सक्षम करता है ), repeat(1000)10 वर्ण स्ट्रिंग पर एक मिलियन बार कॉल करता है।


1

यदि आपको लगता है कि उन सभी प्रोटोटाइप परिभाषाओं, सरणी क्रिएशन और ज्वाइन ऑपरेशन्स ओवरकिल हैं, तो बस एक लाइन कोड का उपयोग करें जहां आपको इसकी आवश्यकता है। स्ट्रिंग एस दोहराता हुआ N:

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

3
कोड पठनीय होना चाहिए। यदि आप शाब्दिक रूप से केवल हर एक बार इसका उपयोग करने जा रहे हैं, तो इसे ठीक से प्रारूपित करें (या Array(N + 1).join(str)विधि का उपयोग करें यदि यह एक प्रदर्शन अड़चन नहीं है)। यदि आप इसे दो बार उपयोग करने जा रहे हैं तो थोड़ा मौका है, इसे उचित रूप से नामित फ़ंक्शन पर ले जाएं।
बादल

1

जावास्क्रिप्ट उपयोगिता कार्यक्षमता के लिए लॉडश का उपयोग करें, जैसे स्ट्रिंग्स को दोहराते हुए।

लोदाश अच्छा प्रदर्शन और ECMAScript अनुकूलता प्रदान करता है।

मैं यूआई विकास के लिए इसकी अत्यधिक अनुशंसा करता हूं और यह अच्छी तरह से सर्वर साइड पर भी काम करता है।

लोड़ेश का उपयोग करके 2 बार स्ट्रिंग "यो" को कैसे दोहराएं:

> _.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

मैं यहाँ बेतरतीब ढंग से आया और पहले कभी जावास्क्रिप्ट में एक चार दोहराने का कारण नहीं था।

मैं आर्टिस्टोक्स के इसे करने के तरीके और प्रभावित परिणामों से प्रभावित था। मैंने देखा कि आखिरी स्ट्रिंग कॉनसैट अनावश्यक था, जैसा कि डेनिस ने भी बताया था।

मैंने देखा कि कुछ और चीजें जब नमूने के साथ खेलती हैं तो एक साथ रखा जाता है।

परिणाम अक्सर एक उचित मात्रा में होता है और अक्सर अंतिम एल्गोरिदम के पक्ष में होता है जो अक्सर स्थिति के लिए जॉकी होता है। जिन चीज़ों में मैंने बदलाव किया उनमें से एक कॉल के लिए बीज के रूप में जेएसएलटाइमस उत्पन्न गणना का उपयोग करने के बजाय थी; जैसा कि गणना विभिन्न तरीकों के लिए अलग-अलग उत्पन्न हुई थी, मैंने एक सूचकांक में डाल दिया। इससे बात और अधिक विश्वसनीय हो गई। मैंने तब यह सुनिश्चित करने के लिए देखा कि अलग-अलग आकार के तार कार्यों के लिए पारित किए गए थे। इसने मेरे द्वारा देखी गई कुछ विविधताओं को रोका, जहां कुछ एल्गोरिदम ने एकल चार्ट या छोटे तारों में बेहतर प्रदर्शन किया। हालांकि शीर्ष 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();

मैंने तब डेनिस को ठीक किया और यह देखने का फैसला किया कि क्या मुझे थोड़ा और बाहर निकालने का रास्ता मिल सकता है।

चूंकि जावास्क्रिप्ट वास्तव में चीजों को अनुकूलित नहीं कर सकता है, इसलिए प्रदर्शन में सुधार करने का सबसे अच्छा तरीका मैन्युअल रूप से चीजों से बचना है। अगर मैंने पहले 4 तुच्छ परिणामों को लूप से बाहर निकाल लिया, तो मैं 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;
}

इससे डेनिस के फिक्स पर औसतन 1-2% सुधार हुआ। हालांकि, अलग-अलग रन और अलग-अलग ब्राउज़र एक उचित पर्याप्त विचरण दिखाते हैं कि यह अतिरिक्त कोड शायद 2 पिछले एल्गोरिदम के प्रयास के लायक नहीं है।

एक चार्ट

संपादित करें: मैंने ऐसा ज्यादातर क्रोम के तहत किया। फ़ायरफ़ॉक्स और IE अक्सर कुछ% द्वारा डेनिस का पक्ष लेंगे।



0

लोग इसे हास्यास्पद हद तक या बेकार प्रदर्शन से अधिक मानते हैं। सरणी? प्रत्यावर्तन? आप मुझसे मज़ाक कर रहे हो।

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

संपादित करें। मैंने कलाकारोक्स / विच्छेदित और अन्य लोगों के झुंड द्वारा पोस्ट किए गए बिटवाइज़ संस्करण के साथ तुलना करने के लिए कुछ सरल परीक्षण किए। उत्तरार्द्ध केवल मामूली रूप से तेज़ था, लेकिन परिमाण के आदेश अधिक स्मृति-कुशल थे। 'ब्लाह' शब्द के 1000000 दोहराव के लिए, नोड प्रक्रिया सरल अवतरण एल्गोरिथ्म (ऊपर) के साथ 46 मेगाबाइट तक गई, लेकिन लॉगरिदमिक एल्गोरिथ्म के साथ केवल 5.5 मेगाबाइट। उत्तरार्द्ध निश्चित रूप से जाने का रास्ता है। स्पष्टता के लिए इसे पुन: प्रस्तुत करना:

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

आपके पास string += stringसमय का एक अनावश्यक हिस्सा है।
निकोलय

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

ईएस 8 के साथ आप इसके लिए padStartया padEndइसका उपयोग कर सकते हैं । जैसे।

var str = 'cat';
var num = 23;
var size = str.length * num;
"".padStart(size, str) // outputs: 'catcatcatcatcatcatcatcatcatcatcatcatcatcatcatcatcatcatcatcatcatcatcat'
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.