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 +?

War es hilfreich?

Lösung

Sie können das tun in mehrfacher Hinsicht:

  1. Wie Sie mit << gezeigt, aber das ist nicht der üblicher Weg
  2. Mit String-Interpolation

    source = "#{ROOT_DIR}/#{project}/App.config"
    
  3. 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}"
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top