String concatenation in Ruby

Posted by Jonas Elfström Mon, 01 Feb 2010 23:04:00 GMT

There's no StringBuilder class in Ruby because the String class has the << for appending. The problem is that not every Ruby programmer seems to be aware of it. Recently I've seen += being used to append to strings where << would have been a much better choice.

The problem with using += is that it creates a new String instance and if you do that in a loop you can get really horrible performance.

If you are dealing with an array you don't even have to use << because Array#join is even faster and shows intent in a nice way.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
require 'benchmark'

array_of_rnd_strings=(0...262144).map{65.+(rand(25)).chr}
                                 .join.scan(/.{1,8}/m)

Benchmark.bm do |benchmark|
  benchmark.report do
    str=array_of_rnd_strings.join
  end
  benchmark.report do
    str2=""
    array_of_rnd_strings.each do |s|
      str2<<s
    end
  end
  benchmark.report do
    str3=""
    array_of_rnd_strings.each do |s|
      str3+=s
    end
  end
end
The array_of_rnd_strings is an array of 32768 8 characters long random strings.

usersystemtotalreal
0.0300000.0000000.030000( 0.027184)
0.1600000.0100000.170000( 0.190277)
106.0200000.300000106.320000(113.457793)


The performance of += was even worse than I imagined!

Posted in Ruby | 5 comments

Comments

    1. Jimmy Tue, 06 Apr 2010 13:10:42 GMT

      Sweet

    2. Avatar
      sapphire Wed, 15 Dec 2010 11:26:08 GMT

      BUT, if our strings are a discrete and well known collection (they are not in an array), the proper method in terms of speed is << or +, not join.

      http://stackoverflow.com/questions/4402336/array-join-versus-string-concatenation-efficiency

    3. Avatar
      Jonas Wed, 15 Dec 2010 22:22:46 GMT

      @sapphire I’m not sure so I like that benchmark. The join example first builds an array and then joins. The concatenation example just concatenates “foobar” over and over. I can’t really map that to a real world scenario. If you can, please show me.

    4. Avatar
      sapphire Thu, 16 Dec 2010 15:52:12 GMT

      just wanted to clarify that there are are different cases. in your benchmarking, you measure the time to join an array, correctly concluding that the best method is join.

      however, join is not the universal method to join strings (as a ruby noob may think), so i put the stackoverflow hyperlink.

      so i you previously have strings in an array, then .join() them. but if you have a discrete well-known number of strings (a, b and c), join them as:

      a << b << c

      ”#{a}#{b}#{c}”

      or

      a + b + c

      but never compose an array and then join them

      [a,b,c].join

      hope my point is clear now :)

    5. Avatar
      Jonas Thu, 16 Dec 2010 23:18:14 GMT

      @sapphire Great explanation and I totally agree.

Comments are closed