Concatenación de cadenas en Ruby


Estoy buscando una forma más elegante de concatenar cadenas en Ruby.

Tengo la siguiente línea:

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

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

¿Y cuál es la diferencia entre << y +?

Author: idmean, 2008-12-18

10 answers

Puedes hacerlo de varias maneras:

  1. Como mostraste con << pero esa no es la forma habitual
  2. Con 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 (sin embargo, no medido). Los tres métodos lanzarán un error constante no inicializado cuando ROOT_DIR es nil.

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

Al final, es una cuestión de gusto.

 492
Author: Keltia,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-01-01 20:14:57

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

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

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"
 83
Author: Matt Burke,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-06-27 02:52:15

Si solo está concatenando rutas, puede usar el propio archivo de Ruby.método de unión.

source = File.join(ROOT_DIR, project, 'App.config')
 74
Author: georg,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-12-18 13:22:32

De http://greyblake.com/blog/2012/09/02/ruby-perfomance-tricks/

Usar << aka concat es mucho más eficiente que +=, ya que este último 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)
 19
Author: Danny,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-07-01 13:02:46

Dado que esta es una ruta, probablemente usaría array y join:

source = [ROOT_DIR, project, 'App.config'] * '/'
 9
Author: Dejan Simic,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-12-18 13:14:23

Aquí hay otro punto de referencia inspirado por esta esencia. Compara la concatenación (+), la adición (<<) y la interpolación (#{}) para cadenas dinámicas y predefinidas.

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: la interpolación en la RM es pesada.

 7
Author: Adobe,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-02-13 18:06:02

Preferiría usar Pathname:

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

Acerca de << y + de ruby docs:

+: Devuelve una nueva Cadena que contiene other_str concatenada a str

<<: Concatena el objeto dado a str. Si el objeto es un Fixnum entre 0 y 255, se convierte en un carácter antes de la concatenación.

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

 6
Author: tig,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-06-27 02:53:14

Déjame mostrarte toda mi experiencia con eso.

Tuve una consulta que devolvió 32k de registros, para cada registro llamé a un método para formatear ese registro de base de datos en una cadena formateada y luego concatenar en una cadena que al final de todo este proceso se convertirá en un archivo en disco.

Mi problema era que por el registro va, alrededor de 24k, el proceso de concatenar la cadena se volvió un dolor.

Estaba haciendo eso usando el '+'normal operador.

Cuando cambié a '

Entonces, recordé mis viejos tiempos - algo así como 1998 - cuando estaba usando Java y concatenando String usando '+' y cambié de String a StringBuffer (y ahora nosotros, desarrolladores de Java tenemos el StringBuilder).

Creo que el proceso de + /

La primera reasigna todo el objeto en la memoria y la otra solo apunta a una nueva dirección.

 6
Author: Marcio Mangar,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-08-03 20:11:33

¿Concatenación dices? ¿Qué tal #concat método entonces?

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

Para ser justos, concat se denomina <<.

 5
Author: Boris Stitnicky,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-06-12 03:48:00

Aquí hay más formas de hacer esto:

"String1" + "String2"

"#{String1} #{String2}"

String1<<String2

Y así sucesivamente ...

 5
Author: Imran Alavi,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-09-25 20:50:49