Pregunta

Busco una forma más elegante de la concatenación de cadenas en Ruby.

Tengo la siguiente línea:

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

¿Hay una manera más agradable de hacer esto?

Y para el caso de lo que es la diferencia entre << y +?

¿Fue útil?

Solución

Puede hacerlo de varias maneras:

  1. Como se muestra con << pero ese no es el habitual manera
  2. Para la interpolación de cadena

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

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

El segundo método parece ser más eficiente en términos de memoria / velocidad de lo que he visto (no se mide sin embargo). Los tres métodos generará un error constante sin inicializar cuando ROOT_DIR es nula.

Cuando se trata de nombres de ruta, es posible que desee utilizar File.join para evitar ensuciar con separador de ruta.

Al final, se trata de una cuestión de gusto.

Otros consejos

El operador + es la opción normal de la concatenación, y es probablemente la manera más rápida para concatenar cadenas.

La diferencia entre + y << es que << cambia el objeto en su mano izquierda, y + no lo hace.

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 se acaba de concatenando caminos que puede utilizar un método propio File.join de Ruby.

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

desde http://greyblake.com/blog/2012/ 09/02 / rubí del perfomance-tricks /

El uso de alias << concat es mucho más eficiente que +=, ya que éste crea un objeto temporal y anula el primer objeto con el nuevo objeto.

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

salida:

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

Dado que este es un camino que probablemente haría uso de la matriz y de Ingreso:

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

Aquí hay otro punto de referencia inspirado en este GIST . Se compara concatenación (+), añadiendo (<<) y la interpolación (#{}) para cuerdas dinámicas y predefinidos.

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

salida:

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)

Conclusión:. Interpolación en la RM es pesado

Yo prefiero usar nombre de ruta:

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

sobre << y + de los documentos del rubí:

+: Devuelve un nueva cadena que contiene other_str concatenado a STR

<<: concatena el objeto dado a str. Si el objeto es un Fixnum entre 0 y 255, que se convierte en un personaje antes de concatenación.

por lo diferencia está en lo que se convierte en primer operando (<< hace cambios en su lugar, + devuelve nueva cadena por lo que es la memoria más pesado) y lo será si el primer operando es Fixnum (<< será agregar como si se tratara de carácter con el código de la igualdad a ese número, + elevará error)

Te voy a enseñar a todos ustedes mi experiencia con eso.

tuve una consulta que devuelve 32k de registros, para cada registro que se llama un método para dar formato a ese registro de base de datos en una cadena con formato y de concatenar que en una cadena que al final de todo este proceso Wil se convierten en un archivo en disco.

Mi problema era que el registro va, alrededor de 24k, el proceso de concatenar la cadena enciende un dolor.

que estaba haciendo que el uso regular de operador '+'.

Cuando cambié a la '<<' era como magia. Fue muy rápido.

Entonces, recordé mis viejos tiempos - clase de 1998 - cuando yo estaba usando Java y la concatenación de cadena usando '+' y cambiado de String a StringBuffer (y ahora, desarrollador de Java tienen el StringBuilder).

Creo que el proceso de + / << en Ruby mundo es el mismo que + / StringBuilder.append en el mundo Java.

La primera reasignar todo el objeto en la memoria y el otro punto justo a una nueva dirección.

La concatenación se dice? ¿Qué tal método #concat entonces?

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

En toda la imparcialidad, concat es alias como <<.

Aquí hay más maneras de hacer esto:

"String1" + "String2"

"#{String1} #{String2}"

String1<<String2

Y así sucesivamente ...

Es posible utilizar + u operador <<, pero en función de rubí .concat es el más preferible uno, ya que es mucho más rápido que otros operadores. Se puede utilizar como.

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

También puede utilizar % de la siguiente manera:

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

Este enfoque funciona con ' marca (individual) cita también.

asuntos situación, por ejemplo:

# 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

En el primer ejemplo, la concatenación con el operador + no actualizará el objeto output, sin embargo, en el segundo ejemplo, el operador << actualizará el objeto output con cada iteración. Por lo tanto, para el mencionado tipo de situación, << es mejor.

Puede concatenar en la definición cadena directamente:

nombre_apellido = "#{customer['first_name']} #{customer['last_name']} #{order_id}"
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top