2016-04-04 12 views
16

में स्ट्रिंग बनाने के लिए वर्णों को जोड़ने का सबसे तेज़, सबसे छोटा तरीका, मैं एक सी # पृष्ठभूमि से आया हूं जहां System.String अपरिवर्तनीय है और स्ट्रिंग कॉन्सटेनेशन अपेक्षाकृत महंगा है (क्योंकि इसे स्ट्रिंग को फिर से चालू करने की आवश्यकता है) हम StringBuilder प्रकार के बजाय इसके रूप में उपयोग करना चाहते हैं एक बड़ा बफर प्रीलोकेट करता है जहां एकल वर्ण (Char, एक 16-बिट मान-प्रकार) और छोटे तारों को अतिरिक्त आवंटन के बिना सस्ती रूप से संयोजित किया जा सकता है।स्विफ्ट

मैं स्विफ्ट में कुछ सी # कोड पोर्ट कर रहा हूं जो बिट-सरणी ([Bool]) से उप-ऑक्टेट इंडेक्स पर पढ़ता है जिसमें 8 बिट्स से कम वर्ण की लंबाई होती है (यह एक बहुत ही स्थान-जागरूक फ़ाइल प्रारूप है)।

मेरे सी # कोड कुछ इस तरह है:

StringBuilder sb = new StringBuilder(expectedCharacterCount); 
int idxInBits = 0; 
Boolean[] bits = ...; 
for(int i = 0; i < someLength; i++) { 
    Char c = ReadNextCharacter(ref idxInBits, 6); // each character is 6 bits in this example 
    sb.Append(c); 
} 

स्विफ्ट में, मुझे लगता है NSMutableString नेट के StringBuilder के बराबर है, और मैं इतना स्विफ्ट में मैं अलग-अलग पात्रों (How to append a character to string in Swift?) जोड़कर के बारे में इस गुणवत्ता आश्वासन मिला इस:

var buffer: NSMutableString 
for i in 0..<charCount { 
    let charValue: Character = readNextCharacter(...) 
    buffer.AppendWithFormat("%c", charValue) 
} 
return String(buffer) 

लेकिन मैं क्यों यह एक प्रारूप स्ट्रिंग के माध्यम से पहली चला जाता है पता नहीं है, अक्षम लगता है कि (हर यात्रा पर प्रारूप स्ट्रिंग reparsing) और के रूप में अपने कोड iOS उपकरणों पर चल रहा है मैं चाहता हूँ बहुत हो मेरे प्रोग्राम के सीपीयू और मेमोरी उपयोग के साथ rvative।

जैसा कि मैंने इस लिख रहा था, मुझे पता चला मेरी कोड वास्तव में UnicodeScalar बजाय Character का उपयोग करना चाहिए, समस्या, NSMutableString है नहीं करता है आप एक UnicodeScalar मूल्य जोड़ें, आप स्विफ्ट के स्वयं के परिवर्तनशील String प्रकार का उपयोग करने के लिए है तो अब मेरी कोड दिखता है जैसे:

var buffer: String 
for i in 0..<charCount { 
    let x: UnicodeScalar = readNextCharacter(...) 
    buffer.append(x) 
} 
return buffer 

मैंने सोचा था कि String अपरिवर्तनीय था, लेकिन मैंने देखा है अपने append विधि रिटर्न Void

मैं अभी भी असहज यह कर, क्योंकि मैं नहीं जानता कि कैसे स्विफ्ट String प्रकार आंतरिक रूप से लागू किया गया है लग रहा है, और मैं नहीं दिख रहा है कि कैसे मैं reallocations से बचने के लिए (यह मानते हुए स्विफ्ट String बढ़ती एल्गोरिथ्म का उपयोग करता) एक बड़े बफर preallocate कर सकते हैं।

+0

स्विफ्ट में, _var_ का अर्थ है _variable_ और _let_ का मतलब _constant_ है। आपके मामले में, एक var स्ट्रिंग म्यूटेबल हो जाएगा और एक स्ट्रिंग स्ट्रिंग अपरिवर्तनीय होगी। चरित्र को एक परिवर्तनीय स्ट्रिंग में भी जोड़ा जा सकता है। प्रीलोकेशन के लिए, आप '[कैरेक्टर] (गिनती: 100, दोहराए गए वैल्यू: "0") का उपयोग कर सकते हैं ताकि' निश्चित लंबाई की वर्ण 'की सरणी बन सके। (और इसे 'स्ट्रिंग (charArray)' का उपयोग करके स्ट्रिंग में वापस कनवर्ट करें। मैं कहूंगा कि इसके लिए कोई ज़रूरत नहीं है। स्विफ्ट में संलग्न करना काफी तेज है। –

+0

इसके लायक होने के लिए, गिटहब पर एक स्विफ्ट स्ट्रिंगबिल्डर गिस्ट है: https://gist.github.com/kristopherjohnson/1fc55e811d944a430289 ऐसा लगता है कि यह सी # स्ट्रिंगबिल्डर वर्ग का सबसेट लागू करने का इरादा है, और मैन्युअल रूप से परिवर्तित होने पर उपयोगी हो सकता है # स्विफ्ट करने के लिए कार्यक्रम। (कम से कम, अगर आप स्विफ्ट शुद्धवादियों को परेशान करने के बारे में चिंतित नहीं हैं जो कोड को "स्विफ्ट रास्ता" करने के लिए फिर से लिखना पसंद करेंगे।) लेकिन दुर्भाग्यवश यह स्विफ्ट 3 से पहले स्विफ्ट के संस्करण के लिए लिखा गया है, लगभग 10 की आवश्यकता है मामूली परिवर्तन मान्य स्विफ्ट के रूप में स्वीकार किए जाते हैं 3. – RenniePet

+0

@ जे। वैंग का मतलब यह नहीं है कि "अपरिवर्तनीय उत्परिवर्तनीय" स्ट्रिंग' का उपयोग 'चलो एक्स: स्ट्रिंग' कथन के साथ किया जाता है? एक परिवर्तनीय स्ट्रिंग बनाम अपरिवर्तनीय स्ट्रिंग का आंतरिक प्रतिनिधित्व बहुत अलग हो सकता है क्योंकि वे विभिन्न परिदृश्यों (जैसे अपरिवर्तनीय सबस्ट्रिंग) के लिए अनुकूलित करते हैं। – Dai

उत्तर

18

(इस उत्तर दस्तावेज और स्रोत कोड स्विफ्ट 2 और 3 के लिए मान्य के आधार पर लिखा गया था: संभवतः अद्यतन और संशोधन एक बार स्विफ्ट 4 आता है की जरूरत है)

स्विफ्ट के बाद से अब है खुला स्रोत, हम कर सकते हैं वास्तव में स्विफ्ट के लिए स्रोत कोड पर एक नजर है: देशी एस String

ऊपर स्रोत से, हम टिप्पणी

/// Growth and Capacity 
/// =================== 
/// 
/// When a string's contiguous storage fills up, new storage must be 
/// allocated and characters must be moved to the new storage. 
/// `String` uses an exponential growth strategy that makes `append` a 
/// constant time operation *when amortized over many invocations*. 

निम्नलिखित है ऊपर देखते हुए, आप स्विफ्ट (append(_: Character), append(_: UniodeScalar) या appendContentsOf(_: String) के माध्यम से यह हो) में जोड़कर पात्रों के प्रदर्शन के बारे में चिंता करने की जरूरत नहीं होनी चाहिए , एक निश्चित String उदाहरण के लिए संगत भंडारण के पुनर्वितरण के रूप में बहुत बार wrt नहीं होना चाहिए इस आवंटन के लिए होने वाले एकल वर्णों की संख्या को जोड़ने के लिए आवश्यक है।

भी ध्यान रखें कि NSMutableString "विशुद्ध रूप से देशी" Swift नहीं है, लेकिन पाट Obj सी वर्गों (Foundation के माध्यम से सुलभ) के परिवार से संबंधित।


एक नोट अपनी टिप्पणी के लिए

"मैंने सोचा था कि String अपरिवर्तनीय था, लेकिन मैंने देखा है इसकी संलग्न विधि रिटर्न Void।"

String है सिर्फ एक (मान) कि परिवर्तनशील है और साथ ही अपरिवर्तनीय गुण

var foo = "foo" // mutable 
let bar = "bar" // immutable 
    /* (both the above inferred to be of type 'String') */ 

शून्य-रिटर्न उदाहरण तरीकों append(_: Character) और append(_: UniodeScalar) परिवर्तनशील द्वारा इस्तेमाल किया जा सकता है, टाइप परिवर्तनशील के लिए उपलब्ध हैं साथ ही अपरिवर्तनीय String उदाहरण, लेकिन स्वाभाविक रूप से बाद वाले लोगों के साथ उनका उपयोग एक संकलन समय त्रुटि

let chars : [Character] = ["b","a","r"] 
foo.append(chars[0]) // "foob" 
bar.append(chars[0]) // error: cannot use mutating member on immutable value ... 
+0

तो प्रदर्शन के संदर्भ में '+' और 'संलग्न 'हैं? क्या है + = "ए" ',' s = s + "a" 'और' s.append ("a") 'वही काम करते हैं? –

+0

@DanM। हम उस प्रश्न का उत्तर देने के लिए stdlib के लिए (खुले) स्रोत पर जा सकते हैं: ['+ =' ऑपरेटर] (https://github.com/apple/swift/blob/master/stdlib/public/core/String.swift # एल 547) 'lhs._core.append (rhs._core)' कहता है। ['+' ऑपरेटर] (https://github.com/apple/swift/blob/master/stdlib/public/core/String.swift#L537) परिणाम रखने के लिए एक नया 'स्ट्रिंग' उदाहरण बनाता है (नाम ' lhs'), उसके बाद 'lhs._core.append (rhs._core)' भी कॉल करता है। अंत में, ['संलग्न करें (...)' विधि] (https://github.com/apple/swift/blob/master/stdlib/public/core/String.swift#L513) सीधे '_core.append (other._core) '। – dfri

+0

... यदि हम '+ =' ऑपरेटर की तुलना 'एपेंड (...)' विधि से करते हैं, तो पूर्व खालीपन के लिए अतिरिक्त जांच करेगा, साथ ही साथ ऑपरेटर विधि के लिए अतिरिक्त 'इनआउट' संदर्भ उत्तीर्ण करेगा, ऐसा कुछ जो बाद में मौजूद नहीं है। इसलिए, उस मामले को छोड़कर जहां 'स्वयं' खाली है, '_ =' ऑपरेटर की तुलना में थोड़ा सा दुबला कार्यान्वयन करने के लिए 'संलग्न (...)' विधि का तर्क दिया जा सकता है, लेकिन मेरा मानना ​​है कि यह नगण्य होना चाहिए। '+' ऑपरेटर एक और कहानी पूरी तरह से है क्योंकि यह एक नया 'इंस्टेंस' आवंटित करता है जो तब रिटर्न देता है: संभव है कि संकलक इसे अनुकूलित कर सके, लेकिन आपको '+ =' ... – dfri