The way I have been building strings is to store the m strings in an Array and then join() it at the end (which should be only O(n)). The m small objects need to be allocated in both cases, the only difference being that we hold on to those and join them later on.
Am I missing something? I have never measured the performance on either of the these operations so I could be off the mark here.
Here's a simple benchmark:
require "benchmark"
n = 100_000
Benchmark.bm(4) do |x|
x.report("<<") do
n.times do
"aaaaa " << "bbbbbb " << "ccccc " << "ddddd " << "eeeee " << "fffff"
end
end
x.report("join") do
n.times do
["aaaaa", "bbbbbb", "ccccc", "ddddd", "eeeee", "fffff"].join(" ")
end
end
end
The results I get for this are: user system total real
<< 0.140000 0.000000 0.140000 ( 0.143750)
join 0.230000 0.000000 0.230000 ( 0.228035)
I'd be interested to see if there were any use cases where the relative performance was reversed. require "benchmark"
n = 100_000
A = "foo " * 20
B = "bar " * 20
C = "baz " * 20
D = "foobar " * 20
STRINGS = [A, B, C, D]
Benchmark.bm(4) do |x|
x.report("<<") do
n.times do
"" << A << B << C << D
end
end
x.report("join") do
n.times do
STRINGS.join
end
end
end
user system total real
<< 0.090000 0.010000 0.100000 ( 0.102411)
join 0.070000 0.010000 0.080000 ( 0.071142) if path =~ %r{^/assets/mobile/img}
...
end
I knew about `%r` but hadn't realized that it escapes forward-slashes while leaving other regex symbols intact. But with the previous explanation of `%q`, in which arbitrary delimiters can be used, it makes sense...curly braces simply replace `/` as the delimiter, and `/` simply retains its non-specialness in regex...saves me a lot of writing `Regex.escape("/path/to")`.Another regex notation that I recently learned (elsewhere) and now love to abuse:
"He is 32-years old"[/\d+/] # => "32"
as opposed to: "He is 32-years old".match(/\d+/)[0] "28 men are 32 years old"[/(\d+) (year|day|month)/, 1] # => "32"> I knew about `%r` but hadn't realized that it escapes forward-slashes while leaving other regex symbols intact.
The correct explanation can also be found in the next sentence of your comment:
> But with the previous explanation of `%q`, in which arbitrary delimiters can be used, it makes sense...curly braces simply replace `/` as the delimiter, and `/` simply retains its non-specialness in regex.
Regexp.new("/foo/bar")
to achieve the desired result but the %r{} shortcut is handier. x ||= y # equivalent to:
x || x = y
it's actually something slightly different (or at least it was some years ago). class Foo
def foo=(object)
puts "foo= called with #{object.inspect}"
@foo = object
end
def foo
puts "foo called"
@foo
end
end
puts "x || x = y"
a = Foo.new
a.foo || a.foo = 1
a.foo || a.foo = 2
puts "\nx = x || y"
b = Foo.new
b.foo = b.foo || 1
b.foo = b.foo || 2
puts "\nx ||= y"
c = Foo.new
c.foo ||= 1
c.foo ||= 2
This outputs: x || x = y
foo called
foo= called with 1
foo called
x = x || y
foo called
foo= called with 1
foo called
foo= called with 1
x ||= y
foo called
foo= called with 1
foo called
and you can see that the output for ||= matches the output for x || x = yFor example, if you try "x || x = y" you will get an exception if x is not defined, but "x ||= y" will work fine. The same is true of constants "X || X = 1" will explode while "X ||= 1" will work fine.