मैं रूबी में कंसट्रेटिंग स्ट्रिंग्स के अधिक सुरुचिपूर्ण तरीके की तलाश में हूं।
मेरी निम्न पंक्ति है:
source = "#{ROOT_DIR}/" << project << "/App.config"
क्या ऐसा करने का एक अच्छा तरीका है?
और उस बात के लिए बीच का अंतर क्या है <<
और +
?
मैं रूबी में कंसट्रेटिंग स्ट्रिंग्स के अधिक सुरुचिपूर्ण तरीके की तलाश में हूं।
मेरी निम्न पंक्ति है:
source = "#{ROOT_DIR}/" << project << "/App.config"
क्या ऐसा करने का एक अच्छा तरीका है?
और उस बात के लिए बीच का अंतर क्या है <<
और +
?
जवाबों:
आप इसे कई तरीकों से कर सकते हैं:
<<
लेकिन वह सामान्य तरीका नहीं हैस्ट्रिंग प्रक्षेप के साथ
source = "#{ROOT_DIR}/#{project}/App.config"
साथ में +
source = "#{ROOT_DIR}/" + project + "/App.config"
दूसरी विधि स्मृति / गति की अवधि से अधिक कुशल लगती है जो मैंने देखा है (हालांकि मापा नहीं गया है)। ROOT_DIR के शून्य होने पर सभी तीन विधियां एक अनइंस्टाल्यूटेड निरंतर त्रुटि को फेंक देगी।
जब पाथनाम के साथ काम करते हैं, तो आप File.join
पाथनाम विभाजक के साथ खिलवाड़ से बचने के लिए उपयोग करना चाह सकते हैं ।
अंत में, यह स्वाद का मामला है।
+
ऑपरेटर सामान्य संयोजन पसंद है, और शायद CONCATENATE तार करने के लिए सबसे तेज़ तरीका है।
के बीच का अंतर +
और <<
वह यह है कि <<
अपने बाएं हाथ की ओर वस्तु बदलता है, और +
नहीं करता है।
irb(main):001:0> s = 'a'
=> "a"
irb(main):002:0> s + 'b'
=> "ab"
irb(main):003:0> s
=> "a"
irb(main):004:0> s << 'b'
=> "ab"
irb(main):005:0> s
=> "ab"
+
और <<
उसी के बारे में होने जा रहे हैं। यदि आप बहुत सारे तार, या वास्तव में बड़े लोगों के साथ काम कर रहे हैं, तो आप अंतर देख सकते हैं। मैं हैरान था कि उन्होंने कैसा प्रदर्शन किया। gist.github.com/2895311
5.times do ... end
प्रत्येक दुभाषिया के लिए सब कुछ एक ब्लॉक में लपेटें ), आप अधिक सटीक परिणामों के साथ समाप्त करेंगे। मेरे परीक्षण ने दिखाया है कि रूबी दुभाषियों के बीच प्रक्षेप सबसे तेज़ विधि है। मुझे उम्मीद <<
है कि यह सबसे तेज होगा, लेकिन इसीलिए हम बेंचमार्क हैं।
से http://greyblake.com/blog/2012/09/02/ruby-perfomance-tricks/
<<
उर्फ concat
का उपयोग करना कहीं अधिक कुशल है +=
, क्योंकि उत्तरार्द्ध एक लौकिक वस्तु बनाता है और नई वस्तु के साथ पहली वस्तु को ओवरराइड करता है।
require 'benchmark'
N = 1000
BASIC_LENGTH = 10
5.times do |factor|
length = BASIC_LENGTH * (10 ** factor)
puts "_" * 60 + "\nLENGTH: #{length}"
Benchmark.bm(10, '+= VS <<') do |x|
concat_report = x.report("+=") do
str1 = ""
str2 = "s" * length
N.times { str1 += str2 }
end
modify_report = x.report("<<") do
str1 = "s"
str2 = "s" * length
N.times { str1 << str2 }
end
[concat_report / modify_report]
end
end
उत्पादन:
____________________________________________________________
LENGTH: 10
user system total real
+= 0.000000 0.000000 0.000000 ( 0.004671)
<< 0.000000 0.000000 0.000000 ( 0.000176)
+= VS << NaN NaN NaN ( 26.508796)
____________________________________________________________
LENGTH: 100
user system total real
+= 0.020000 0.000000 0.020000 ( 0.022995)
<< 0.000000 0.000000 0.000000 ( 0.000226)
+= VS << Inf NaN NaN (101.845829)
____________________________________________________________
LENGTH: 1000
user system total real
+= 0.270000 0.120000 0.390000 ( 0.390888)
<< 0.000000 0.000000 0.000000 ( 0.001730)
+= VS << Inf Inf NaN (225.920077)
____________________________________________________________
LENGTH: 10000
user system total real
+= 3.660000 1.570000 5.230000 ( 5.233861)
<< 0.000000 0.010000 0.010000 ( 0.015099)
+= VS << Inf 157.000000 NaN (346.629692)
____________________________________________________________
LENGTH: 100000
user system total real
+= 31.270000 16.990000 48.260000 ( 48.328511)
<< 0.050000 0.050000 0.100000 ( 0.105993)
+= VS << 625.400000 339.800000 NaN (455.961373)
चूंकि यह एक ऐसा मार्ग है, जिसका उपयोग मैं संभवतः सरणी का उपयोग करूंगा और इसमें शामिल होऊंगा:
source = [ROOT_DIR, project, 'App.config'] * '/'
यहाँ एक और बेंचमार्क है जो इस जिस्ट से प्रेरित है । यह गतिशील और पूर्वनिर्धारित तारों के लिए संघनन ( +
), संलग्न ( <<
) और प्रक्षेप ( #{}
) की तुलना करता है ।
require 'benchmark'
# we will need the CAPTION and FORMAT constants:
include Benchmark
count = 100_000
puts "Dynamic strings"
Benchmark.benchmark(CAPTION, 7, FORMAT) do |bm|
bm.report("concat") { count.times { 11.to_s + '/' + 12.to_s } }
bm.report("append") { count.times { 11.to_s << '/' << 12.to_s } }
bm.report("interp") { count.times { "#{11}/#{12}" } }
end
puts "\nPredefined strings"
s11 = "11"
s12 = "12"
Benchmark.benchmark(CAPTION, 7, FORMAT) do |bm|
bm.report("concat") { count.times { s11 + '/' + s12 } }
bm.report("append") { count.times { s11 << '/' << s12 } }
bm.report("interp") { count.times { "#{s11}/#{s12}" } }
end
उत्पादन:
Dynamic strings
user system total real
concat 0.050000 0.000000 0.050000 ( 0.047770)
append 0.040000 0.000000 0.040000 ( 0.042724)
interp 0.050000 0.000000 0.050000 ( 0.051736)
Predefined strings
user system total real
concat 0.030000 0.000000 0.030000 ( 0.024888)
append 0.020000 0.000000 0.020000 ( 0.023373)
interp 3.160000 0.160000 3.320000 ( 3.311253)
निष्कर्ष: एमआरआई में प्रक्षेप भारी है।
मैं पथनाम का उपयोग करना पसंद करूंगा:
require 'pathname' # pathname is in stdlib
Pathname(ROOT_DIR) + project + 'App.config'
रूबी डॉक्स के बारे में <<
और +
:
+
: एक नया लौटाता है स्ट्रिंग जिसमें str के साथ अन्य_स्ट्रैट सम्मिलित है
<<
: दिए गए ऑब्जेक्ट को str से सम्मिलित करता है। यदि ऑब्जेक्ट 0 और 255 के बीच एक फ़िक्नम है, तो इसे कॉन्सेप्टेशन से पहले एक कैरेक्टर में बदल दिया जाता है।
इतना अंतर पहले ऑपरेंड में क्या होता है (<<
स्थान में परिवर्तन करता है, +
नई स्ट्रिंग लौटाता है इसलिए यह मेमोरी भारी होती है) और क्या होगा यदि पहला ऑपरेंड फिक्सनम है ( <<
जैसे कि यह उस नंबर के बराबर कोड वाला वर्ण था, +
बढ़ा देगा त्रुटि)
Pathname('/home/foo') + '/etc/passwd' # => #<Pathname:/etc/passwd>
। यह डिजाइन द्वारा है, रूबिडोक उदाहरण पर आधारित है। लगता है कि File.join सुरक्षित है।
(Pathname(ROOT_DIR) + project + 'App.config').to_s
यदि आप एक स्ट्रिंग ऑब्जेक्ट वापस करना चाहते हैं तो आपको कॉल करने की भी आवश्यकता है ।
मुझे उस के साथ अपने सभी अनुभव दिखाते हैं।
मेरे पास एक क्वेरी थी जो 32k रिकॉर्ड्स को लौटाती थी, प्रत्येक रिकॉर्ड के लिए मैंने उस फॉर्मेट को रिकॉर्ड करने के लिए एक फॉर्मेटेड स्ट्रिंग में और कॉन्कैटनेट के बजाय एक स्ट्रिंग में फॉर्मेट करने के लिए कहा था कि इस सारी प्रक्रिया के अंत में डिस्क में एक फाइल में बदल जाता है।
मेरी समस्या यह थी कि रिकॉर्ड के अनुसार, 24k के आसपास, स्ट्रिंग को सुगम बनाने की प्रक्रिया दर्द में बदल गई।
मैं नियमित '+' ऑपरेटर का उपयोग कर रहा था।
जब मैं बदलकर '<<' जादू की तरह था। सचमुच तेज था।
इसलिए, मैंने अपने पुराने समय को याद किया - 1998 का प्रकार - जब मैं जावा का उपयोग कर रहा था और स्ट्रिंग को '+' का उपयोग कर रहा था और स्ट्रिंग से स्ट्रिंगबफ़र में बदल गया (और अब हम, जावा डेवलपर के पास स्ट्रिंगब्यूलर है)।
मेरा मानना है कि रूबी दुनिया में + / << की प्रक्रिया जावा दुनिया में + / StringBuilder.append जैसी ही है।
पहला पूरे ऑब्जेक्ट को मेमोरी में पुनः लोड करता है और दूसरा सिर्फ एक नए पते पर इंगित करता है।
कॉनटेनटेशन आप कहते हैं? #concat
तो विधि के बारे में कैसे ?
a = 'foo'
a.object_id #=> some number
a.concat 'bar' #=> foobar
a.object_id #=> same as before -- string a remains the same object
सभी निष्पक्षता में, के concat
रूप में अलियास है <<
।
"foo" "bar" 'baz" #=> "foobarabaz"
यह करने के लिए और तरीके हैं:
"String1" + "String2"
"#{String1} #{String2}"
String1<<String2
और इसी तरह ...
आप उपयोग +
या <<
संचालक कर सकते हैं , लेकिन रूबी .concat
समारोह में सबसे बेहतर है, क्योंकि यह अन्य ऑपरेटरों की तुलना में बहुत तेज है। आप इसका उपयोग कर सकते हैं।
source = "#{ROOT_DIR}/".concat(project.concat("/App.config"))
.
आपके आखिरी concat
नंबर के बाद आपके पास एक अतिरिक्त है ?
उदाहरण के लिए स्थिति,
# this will not work
output = ''
Users.all.each do |user|
output + "#{user.email}\n"
end
# the output will be ''
puts output
# this will do the job
output = ''
Users.all.each do |user|
output << "#{user.email}\n"
end
# will get the desired output
puts output
पहले उदाहरण में, +
ऑपरेटर के साथ सहमति करने से output
ऑब्जेक्ट अपडेट नहीं होगा , हालांकि, दूसरे उदाहरण में, <<
ऑपरेटर output
प्रत्येक पुनरावृत्ति के साथ ऑब्जेक्ट को अपडेट करेगा । तो, उपरोक्त प्रकार की स्थिति के लिए, <<
बेहतर है।
अपने विशेष मामले के लिए आप Array#join
स्ट्रिंग के पथ पथ प्रकार का निर्माण करते समय भी उपयोग कर सकते हैं :
string = [ROOT_DIR, project, 'App.config'].join('/')]
यह विभिन्न प्रकारों को स्वचालित रूप से स्ट्रिंग में परिवर्तित करने का सुखद पक्ष प्रभाव रखता है:
['foo', :bar, 1].join('/')
=>"foo/bar/1"