Question

Je cherche une façon plus élégante de cordes concaténer en Ruby.

J'ai la ligne suivante:

source = "#{ROOT_DIR}/" << project << "/App.config"

Y at-il une plus belle façon de le faire?

Et d'ailleurs quelle est la différence entre << et +?

Était-ce utile?

La solution

Vous pouvez le faire de plusieurs façons:

  1. Comme vous montré avec << mais ce n'est pas le façon habituelle
  2. Avec l'interpolation de chaîne

    source = "#{ROOT_DIR}/#{project}/App.config"
    
  3. avec +

    source = "#{ROOT_DIR}/" + project + "/App.config"
    

La seconde méthode semble être plus efficace en terme de mémoire / vitesse de ce que j'ai vu (ne se mesure pas bien). Les trois méthodes jetteront une erreur constante lorsque non initialisée ROOT_DIR est nul.

Lorsque vous traitez avec noms de fichiers, vous pouvez utiliser File.join pour éviter de déconner avec séparateur de chemin.

En fin de compte, il est une question de goût.

Autres conseils

L'opérateur + est le choix de concaténation normale, et est probablement le meilleur moyen de concaténer des chaînes.

La différence entre + et << est que << change l'objet sur son côté gauche, et + ne fonctionne pas.

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"

Si vous êtes des chemins concaténez vous pouvez utiliser propre méthode File.join Ruby.

source = File.join(ROOT_DIR, project, 'App.config')

de http://greyblake.com/blog/2012/ 09/02 / ruby-perfomance-tours /

Utilisation << aka concat est beaucoup plus efficace que +=, que celui-ci crée un objet temporel et remplace le premier objet avec le nouvel objet.

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

sortie:

____________________________________________________________
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)

Puisque c'est un chemin que je serais probablement utiliser le tableau et nous rejoindre:

source = [ROOT_DIR, project, 'App.config'] * '/'

Voici une autre référence inspirée par ce point essentiel . Il compare concaténation (+), ajout (<<) et interpolation (#{}) pour les chaînes et dynamiques prédéfinis.

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

sortie:

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)

Conclusion:. Interpolation en IRM est lourde

Je préfère utiliser Pathname:

require 'pathname' # pathname is in stdlib
Pathname(ROOT_DIR) + project + 'App.config'

à propos << et + de docs rubis:

+: Retourne nouveau Chaîne contenant other_str concaténé à str

<<: Concatène l'objet donné à str. Si l'objet est un Fixnum entre 0 et 255, il est converti en un caractère avant concaténation.

différence est dans ce qui devient de premier opérande (<< apporte des modifications en place, + retourne nouvelle chaîne il est donc mémoire plus lourd) et ce sera si le premier opérande est Fixnum (<< ajoutera comme si elle était de caractère avec le code égal à ce numéro, + soulèvera erreur)

Laissez-moi vous montrer à toute mon expérience avec cela.

J'ai eu une requête qui a renvoyé 32k des dossiers, pour chaque enregistrement que j'ai appelé une méthode pour formater cet enregistrement de base de données dans une chaîne formatée et que concaténer que dans une chaîne à la fin de tout ce processus wil se transformer en un fichier disque.

Mon problème était que le dossier va, autour de 24k, le processus de concaténer la chaîne activée une douleur.

Je faisais cela en utilisant l'opérateur '+' régulier.

Quand j'ai changé le « << » était comme par magie. Était vraiment rapide.

Alors, je me suis rappelé mes vieux temps - sorte de 1998 - quand j'utilisais Java et concaténer String à l'aide « + » et changé de chaîne à StringBuffer (et maintenant nous, développeur Java ont StringBuilder).

Je crois que le processus de + / << dans le monde Ruby est le même que + / StringBuilder.append dans le monde Java.

La première réallouer l'objet entier en mémoire et l'autre point seulement à une nouvelle adresse.

Enchaînement vous dites? Que diriez-vous de la méthode #concat alors?

a = 'foo'
a.object_id #=> some number
a.concat 'bar' #=> foobar
a.object_id #=> same as before -- string a remains the same object

En toute équité, concat est Lissé comme <<.

Voici d'autres façons de le faire:

"String1" + "String2"

"#{String1} #{String2}"

String1<<String2

Et ainsi de suite ...

Vous pouvez utiliser + ou opérateur <<, mais en fonction de .concat rubis est la plus préférable, car il est beaucoup plus rapide que d'autres opérateurs. Vous pouvez l'utiliser comme.

source = "#{ROOT_DIR}/".concat(project.concat.("/App.config"))

Vous pouvez également utiliser % comme suit:

source = "#{ROOT_DIR}/%s/App.config" % project

Cette approche fonctionne avec guillemet ' (unique), ainsi.

questions de situation, par exemple:

# 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

Dans le premier exemple, concaténer avec l'opérateur + mettra pas à jour l'objet output, cependant, dans le second exemple, l'opérateur << mettra à jour l'objet output à chaque itération. Donc, pour le type de situation ci-dessus, << est mieux.

Vous pouvez concaténer dans la définition de chaîne directement:

nombre_apellido = "#{customer['first_name']} #{customer['last_name']} #{order_id}"
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top