Some benchmarks are in order.
Because Perry Horwich's answer is basically the same as Huluk's, I figured they'd have the same results. Heh, I was wrong. After looking at it and realizing it was doing a string search instead of a regex, I fixed it and added the fixed test.
After that, I did some fiddling to see what I could come up with. My solutions don't seem to be as straightforward as others, but the first does the job equally fast for short strings, maybe a tiny bit faster on the long strings. The second two are a wash as far as when dealing with short string or long, but both are very fast. I reverted to old-school techniques and did them how we'd do it in assembler "back in the day."
require 'benchmark'
n = 1_000_000
def huluk(s)
s.sub %r{/+$}, ''
end
def apneadiving1(your_string)
matches = your_string.match(/(.*?)\/*$/)
matches[1]
end
def apneadiving2(your_string)
your_string.scan(/(.*?)\/*$/).flatten.first
end
def fixed_perry_horwich(my_beginning_string)
my_beginning_string.sub(/\/+$/,'')
end
def the_tin_man1(s)
s.split(%r[/+$]).first
end
def the_tin_man2(s)
s = s[0..-2] while s[-1] == '/'
s
end
def the_tin_man3(s)
s_len = s.length - 1
s_len -= 1 while s[s_len] == '/'
s[0..s_len]
end
puts "Ruby #{ RUBY_VERSION }"
puts "#{ n } iterations"
puts
[
'abc//',
'abc' * 50 + '//',
'abc' * 10 + '////',
'////////////'
].each do |sample_string|
puts "sample string: #{ sample_string }"
puts 'huluk: %s' % huluk(sample_string)
puts 'perry_horwich: %s' % perry_horwich(sample_string)
puts 'fixed_perry_horwich: %s' % fixed_perry_horwich(sample_string)
puts 'apneadiving1: %s' % apneadiving1(sample_string)
puts 'apneadiving2: %s' % apneadiving2(sample_string)
puts 'the_tin_man1: %s' % the_tin_man1(sample_string)
puts 'the_tin_man2: %s' % the_tin_man2(sample_string)
puts 'the_tin_man3: %s' % the_tin_man3(sample_string)
puts
Benchmark.bm(19) do |b|
2.times do
b.report('huluk') { n.times { huluk(sample_string) } }
b.report('fixed_perry_horwich') { n.times { fixed_perry_horwich(sample_string) } }
b.report('apneadiving1') { n.times { apneadiving1(sample_string) } }
b.report('apneadiving2') { n.times { apneadiving2(sample_string) } }
b.report('the_tin_man1') { n.times { the_tin_man1(sample_string) } }
b.report('the_tin_man2') { n.times { the_tin_man2(sample_string) } }
b.report('the_tin_man3') { n.times { the_tin_man3(sample_string) } }
puts
end
end
puts
end
Results:
Ruby 1.9.3
1000000 iterations
sample string: abc//
huluk: abc
perry_horwich: abc//
fixed_perry_horwich: abc
apneadiving1: abc
apneadiving2: abc
the_tin_man1: abc
the_tin_man2: abc
the_tin_man3: abc
user system total real
huluk 1.840000 0.000000 1.840000 ( 1.849929)
fixed_perry_horwich 1.840000 0.010000 1.850000 ( 1.847069)
apneadiving1 1.900000 0.010000 1.910000 ( 1.900817)
apneadiving2 4.860000 0.010000 4.870000 ( 4.883103)
the_tin_man1 1.830000 0.000000 1.830000 ( 1.826547)
the_tin_man2 1.150000 0.000000 1.150000 ( 1.151420)
the_tin_man3 1.170000 0.010000 1.180000 ( 1.168161)
huluk 1.820000 0.000000 1.820000 ( 1.825440)
fixed_perry_horwich 1.830000 0.000000 1.830000 ( 1.827306)
apneadiving1 1.850000 0.000000 1.850000 ( 1.853751)
apneadiving2 4.830000 0.000000 4.830000 ( 4.825394)
the_tin_man1 1.810000 0.000000 1.810000 ( 1.811503)
the_tin_man2 1.150000 0.000000 1.150000 ( 1.151865)
the_tin_man3 1.170000 0.000000 1.170000 ( 1.172259)
sample string: abcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabc//
huluk: abcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabc
perry_horwich: abcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabc//
fixed_perry_horwich: abcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabc
apneadiving1: abcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabc
apneadiving2: abcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabc
the_tin_man1: abcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabc
the_tin_man2: abcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabc
the_tin_man3: abcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabc
user system total real
huluk 2.120000 0.000000 2.120000 ( 2.122156)
fixed_perry_horwich 2.130000 0.010000 2.140000 ( 2.136665)
apneadiving1 9.630000 0.030000 9.660000 ( 9.656817)
apneadiving2 12.420000 0.030000 12.450000 ( 12.459432)
the_tin_man1 2.080000 0.010000 2.090000 ( 2.090112)
the_tin_man2 1.570000 0.010000 1.580000 ( 1.573887)
the_tin_man3 1.380000 0.000000 1.380000 ( 1.388120)
huluk 2.130000 0.010000 2.140000 ( 2.134414)
fixed_perry_horwich 2.120000 0.010000 2.130000 ( 2.129399)
apneadiving1 9.620000 0.020000 9.640000 ( 9.646624)
apneadiving2 12.410000 0.020000 12.430000 ( 12.423327)
the_tin_man1 2.080000 0.010000 2.090000 ( 2.090938)
the_tin_man2 1.580000 0.010000 1.590000 ( 1.581131)
the_tin_man3 1.390000 0.000000 1.390000 ( 1.400093)
sample string: abcabcabcabcabcabcabcabcabcabc////
huluk: abcabcabcabcabcabcabcabcabcabc
perry_horwich: abcabcabcabcabcabcabcabcabcabc////
fixed_perry_horwich: abcabcabcabcabcabcabcabcabcabc
apneadiving1: abcabcabcabcabcabcabcabcabcabc
apneadiving2: abcabcabcabcabcabcabcabcabcabc
the_tin_man1: abcabcabcabcabcabcabcabcabcabc
the_tin_man2: abcabcabcabcabcabcabcabcabcabc
the_tin_man3: abcabcabcabcabcabcabcabcabcabc
user system total real
huluk 1.980000 0.010000 1.990000 ( 1.983149)
fixed_perry_horwich 1.970000 0.010000 1.980000 ( 1.979796)
apneadiving1 3.500000 0.010000 3.510000 ( 3.513885)
apneadiving2 6.320000 0.020000 6.340000 ( 6.348327)
the_tin_man1 2.070000 0.010000 2.080000 ( 2.075045)
the_tin_man2 2.800000 0.000000 2.800000 ( 2.801136)
the_tin_man3 1.840000 0.010000 1.850000 ( 1.851506)
huluk 1.980000 0.010000 1.990000 ( 1.980867)
fixed_perry_horwich 1.980000 0.010000 1.990000 ( 1.984776)
apneadiving1 3.510000 0.010000 3.520000 ( 3.523383)
apneadiving2 6.340000 0.020000 6.360000 ( 6.357442)
the_tin_man1 2.070000 0.000000 2.070000 ( 2.074559)
the_tin_man2 2.800000 0.010000 2.810000 ( 2.814275)
the_tin_man3 1.850000 0.010000 1.860000 ( 1.855621)
sample string: ////////////
huluk:
perry_horwich: ////////////
fixed_perry_horwich:
apneadiving1:
apneadiving2:
the_tin_man1:
the_tin_man2:
the_tin_man3:
user system total real
huluk 1.980000 0.010000 1.990000 ( 1.982700)
fixed_perry_horwich 1.980000 0.010000 1.990000 ( 1.984354)
apneadiving1 1.860000 0.000000 1.860000 ( 1.869155)
apneadiving2 4.840000 0.020000 4.860000 ( 4.852445)
the_tin_man1 2.010000 0.000000 2.010000 ( 2.020292)
the_tin_man2 5.060000 0.020000 5.080000 ( 5.070202)
the_tin_man3 6.390000 0.020000 6.410000 ( 6.412697)
huluk 1.980000 0.010000 1.990000 ( 1.987652)
fixed_perry_horwich 1.980000 0.010000 1.990000 ( 1.981360)
apneadiving1 1.860000 0.000000 1.860000 ( 1.871577)
apneadiving2 4.850000 0.020000 4.870000 ( 4.857329)
the_tin_man1 2.010000 0.010000 2.020000 ( 2.023877)
the_tin_man2 5.060000 0.010000 5.070000 ( 5.067753)
the_tin_man3 6.410000 0.020000 6.430000 ( 6.434523)
I tried to bracket the simple case of "abc//"
and something I'd consider a "worser-case" of 152 characters, to antagonize the patterns and algorithms presented.
huluk
and fixed_perry_horwich
are a wash as far as which is faster, because the difference between them is compiled away as the source is interpreted by Ruby.
EDIT:
A couple changes:
- I refactored the code to DRY it up.
- I removed the
perry_horwich
test from the benchmarks, because it made no sense to test it.
- I added a test for
'////////////'
at @pguardiario's recommendation. It shows the result of a worst-case test stripping the delimiters.
The take-away from the test results is to look at the sort of data being tested and select the algorithm that works best for the input. What works well for some inputs doesn't necessarily work as well for others. I found it interesting that the "old-school" methods outran solutions using regex for short trailing-delimiter strings. I think that's a result of Ruby setting up the calls to compiled code. Once the delimiter string got longer, the compiled code would have an advantage.