String-Verkettung in Rubin
-
22-08-2019 - |
Frage
Ich bin für eine elegantere Möglichkeit Strings in Ruby verketten.
Ich habe die folgende Zeile:
source = "#{ROOT_DIR}/" << project << "/App.config"
Gibt es eine schönere Art und Weise, dies zu tun?
Und was das betrifft, was ist der Unterschied zwischen <<
und +
?
Lösung
Sie können das tun in mehrfacher Hinsicht:
- Wie Sie mit
<<
gezeigt, aber das ist nicht der üblicher Weg -
Mit String-Interpolation
source = "#{ROOT_DIR}/#{project}/App.config"
-
mit
+
source = "#{ROOT_DIR}/" + project + "/App.config"
Die zweite Methode scheint aus in der Bezeichnung der Speicher / Geschwindigkeit, effizienter zu sein, was ich gesehen habe (allerdings nicht gemessen). Alle drei Methoden wird eine nicht initialisierte konstanten Fehler werfen, wenn ROOT_DIR Null ist.
Wenn Sie mit Pfadnamen tun haben, können Sie File.join
verwenden, um mit Pfadtrenn zu vermeiden vermasselt.
Am Ende ist es eine Frage des Geschmacks.
Andere Tipps
Der +
Operator ist die normale Verkettung Wahl und ist wahrscheinlich der schnellste Weg, Strings zu verketten.
Der Unterschied zwischen +
und <<
ist, dass <<
das Objekt auf seiner linken Seite ändert und +
nicht.
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"
Wenn Sie nur Pfade verketten Sie Rubys eigene File.join Methode verwenden können.
source = File.join(ROOT_DIR, project, 'App.config')
http://greyblake.com/blog/2012/ 02.09 / ruby-perfomance-Tricks /
<<
aka concat
Verwendung ist wesentlich effizienter als +=
, da letztere ein zeitliches Objekt erstellt und überschreibt das erste Objekt mit dem neuen Objekt.
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
Ausgabe:
____________________________________________________________
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)
Da dies ein Weg, den ich wahrscheinlich Array verwenden würde und kommen:
source = [ROOT_DIR, project, 'App.config'] * '/'
Hier ist ein weiterer Benchmark von diesem Kern inspiriert. Es vergleicht Verkettung (+
), Anfügen (<<
) und Interpolation (#{}
) für dynamische und vordefinierten Zeichenketten.
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
Ausgabe:
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)
. Fazit: Interpolation in der MRT ist schwer
Ich würde es vorziehen Pathname mit:
require 'pathname' # pathname is in stdlib
Pathname(ROOT_DIR) + project + 'App.config'
über <<
und +
von Ruby-Dokumentation:
+
: Liefert ein neue String mit other_str verketteten auf str
<<
: Verknüpft das angegebene Objekt zu str. Wenn das Objekt ein Fixnum zwischen 0 und 255 ist, ist es zu einem Zeichen vor Verkettung umgewandelt wird.
so Unterschied in ist, was zu ersten Operanden wird (<<
nimmt Änderungen an Ort und Stelle, kehrt +
neue Zeichenfolge, so dass es Speicher ist schwerer) und was sein wird, wenn der erste Operand Fixnum (<<
ist fügt, als ob es Zeichen mit dem Code war gleich auf diese Zahl, wird +
erhöhen Fehler)
Lassen Sie mich Ihnen zeigen, alle meine Erfahrungen mit dem.
hatte ich eine Abfrage, die 32k Datensätze zurückgegeben, für jeden Datensatz ich eine Methode namens diese Datenbank Datensatz in eine formatierte Zeichenfolge zu formatieren und als die in eine String verketten, dass dieser Prozess am Ende alle in eine Datei drehen wil in Platte.
Mein Problem war, dass durch die Platte geht, um 24k, der Prozess die String verketten auf einem Schmerz verwandelt.
ich tat, dass der regelmäßigen '+' Operator.
Als ich das geändert ‚<<‘ war wie Magie. War wirklich schnell.
Also, ich meine alte Zeiten erinnert - eine Art 1998 - wenn ich Java wurde mit und verketten String mit ‚+‘ und von String in String geändert (und jetzt wir, Java-Entwickler haben die Stringbuilder).
Ich glaube, dass der Prozess von + / << in Ruby Welt ist die gleiche wie + / StringBuilder.append in der Java-Welt.
Das erste das gesamte Objekt im Speicher und den anderen nur Punkt zu einer neuen Adresse neu zuweisen.
Verkettungs Sie sagen? Wie wäre es #concat
Methode dann?
a = 'foo'
a.object_id #=> some number
a.concat 'bar' #=> foobar
a.object_id #=> same as before -- string a remains the same object
In allen Fairness, concat
ist aliased als <<
.
Hier sind weitere Möglichkeiten, dies zu tun:
"String1" + "String2"
"#{String1} #{String2}"
String1<<String2
Und so weiter ...
Sie können verwenden +
oder <<
Operator, aber in Ruby .concat
Funktion ist das am meisten bevorzugte, da es viel schneller als andere Betreiber ist. Sie können es gerne verwenden.
source = "#{ROOT_DIR}/".concat(project.concat.("/App.config"))
Sie können auch %
wie folgt verwenden:
source = "#{ROOT_DIR}/%s/App.config" % project
Dieser Ansatz funktioniert mit '
(single) Anführungszeichen als auch.
Situation Fragen, zum Beispiel:
# 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
Im ersten Beispiel, mit +
Operator verketten das output
Objekt nicht aktualisiert werden, jedoch in dem zweiten Beispiel der <<
Betreiber das output
Objekt mit jeder Iteration aktualisiert werden. Also, für die obige Art von Situation, <<
ist besser.
Sie können in String Definition verketten direkt:
nombre_apellido = "#{customer['first_name']} #{customer['last_name']} #{order_id}"