String concatenation in Ruby

前端 未结 16 1030
青春惊慌失措
青春惊慌失措 2020-11-28 01:28

I am looking for a more elegant way of concatenating strings in Ruby.

I have the following line:

source = \"#{ROOT_DIR}/\" << project <<          


        
相关标签:
16条回答
  • 2020-11-28 01:34

    Let me show to you all my experience with that.

    I had an query that returned 32k of records, for each record I called a method to format that database record into a formated string and than concatenate that into a String that at the end of all this process wil turn into a file in disk.

    My problem was that by the record goes, around 24k, the process of concatenating the String turned on a pain.

    I was doing that using the regular '+' operator.

    When I changed to the '<<' was like magic. Was really fast.

    So, I remembered my old times - sort of 1998 - when I was using Java and concatenating String using '+' and changed from String to StringBuffer (and now we, Java developer have the StringBuilder).

    I believe that the process of + / << in Ruby world is the same as + / StringBuilder.append in the Java world.

    The first reallocate the entire object in memory and the other just point to a new address.

    0 讨论(0)
  • 2020-11-28 01:34

    For Puppet:

    $username = 'lala'
    notify { "Hello ${username.capitalize}":
        withpath => false,
    }
    
    0 讨论(0)
  • 2020-11-28 01:35

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

    Using << aka concat is far more efficient than +=, as the latter creates a temporal object and overrides the first object with the new object.

    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
    

    output:

    ____________________________________________________________
    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)
    
    0 讨论(0)
  • 2020-11-28 01:36

    The + operator is the normal concatenation choice, and is probably the fastest way to concatenate strings.

    The difference between + and << is that << changes the object on its left hand side, and + doesn't.

    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"
    
    0 讨论(0)
  • 2020-11-28 01:37

    You can do that in several ways:

    1. As you shown with << but that is not the usual way
    2. With string interpolation

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

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

    The second method seems to be more efficient in term of memory/speed from what I've seen (not measured though). All three methods will throw an uninitialized constant error when ROOT_DIR is nil.

    When dealing with pathnames, you may want to use File.join to avoid messing up with pathname separator.

    In the end, it is a matter of taste.

    0 讨论(0)
  • 2020-11-28 01:38

    Since this is a path I'd probably use array and join:

    source = [ROOT_DIR, project, 'App.config'] * '/'
    
    0 讨论(0)
提交回复
热议问题