6

Ruby 类中是否有任何内置函数String可以为我提供 Ruby 中字符串的所有前缀。就像是:

"ruby".all_prefixes => ["ruby", "rub", "ru", "r"]

目前我为此做了一个自定义函数:

def all_prefixes search_string
  dup_string = search_string.dup
  return_list = []
  while(dup_string.length != 0)
    return_list << dup_string.dup
    dup_string.chop!
  end 
 return_list 
end

但我正在寻找更类似于 ruby​​、更少代码和更神奇的东西。注意:当然不用说original_string应该保持原样。

4

9 回答 9

9

不,没有内置的方法。你可以这样做:

def all_prefixes(string)
  string.size.times.collect { |i| string[0..i] }
end
all_prefixes('ruby')
# => ["r", "ru", "rub", "ruby"] 
于 2013-08-06T10:35:25.790 回答
7

快速基准测试:

require 'fruity'

string = 'ruby'

compare do   

  toro2k do
    string.size.times.collect { |i| string[0..i] }
  end

  marek_lipka do
    (0...(string.length)).map{ |i| string[0..i] }
  end

  jorg_w_mittag do
    string.chars.inject([[], '']) { |(res, memo), c| 
      [res << memo += c, memo] 
    }.first
  end

  jorg_w_mittag_2 do
    acc = ''
    string.chars.map {|c| acc += c }
  end

  stefan do
    Array.new(string.size) { |i| string[0..i] }
  end

end

最终获胜者是:

Running each test 512 times. Test will take about 1 second.
jorg_w_mittag_2 is faster than stefan by 19.999999999999996% ± 10.0%
stefan is faster than marek_lipka by 10.000000000000009% ± 10.0%
marek_lipka is faster than jorg_w_mittag by 10.000000000000009% ± 1.0%
jorg_w_mittag is similar to toro2k
于 2013-08-06T11:06:13.317 回答
6
def all_prefixes(str)
  acc = ''
  str.chars.map {|c| acc += c }
end
于 2013-08-06T10:53:06.960 回答
5

关于什么

str = "ruby"
prefixes = Array.new(str.size) { |i| str[0..i] }  #=> ["r", "ru", "rub", "ruby"]
于 2013-08-06T10:52:23.347 回答
4

这可能是一个长镜头,但如果你想为一组字符串找到不同的缩写,你可以使用该Abbrev模块:

require 'abbrev'

Abbrev.abbrev(['ruby']).keys
=> ["rub", "ru", "r", "ruby"]
于 2013-08-06T11:39:08.133 回答
3

稍微短一点的形式:

def all_prefixes(search_string)
  (0...(search_string.length)).map{ |i| search_string[0..i] }
end
all_prefixes 'ruby'
# => ["r", "ru", "rub", "ruby"]
于 2013-08-06T10:31:55.490 回答
1
def all_prefixes(str)
  str.chars.inject([[], '']) {|(res, memo), c| [res << memo += c, memo] }.first
end
于 2013-08-06T10:44:11.037 回答
1
str = "ruby"    
prefixes = str.size.times.map { |i| str[0..i] }  #=> ["r", "ru", "rub", "ruby"]
于 2013-08-06T11:17:00.630 回答
0

之前没有提到的两个比@toro2k 接受的比较答案中的更快。

(1..s.size).map { |i| s[0, i] }
=> ["r", "ru", "rub", "ruby"]

Array.new(s.size) { |i| s[0, i+1] }
=> ["r", "ru", "rub", "ruby"]

奇怪的是,以前没有人用过String#[start, length],只有较慢的String#[range]
而且我认为至少我的第一个解决方案非常简单。

基准测试结果(使用 Ruby 2.4.2):

                           user     system      total        real
toro2k                14.594000   0.000000  14.594000 ( 14.724630)
marek_lipka           12.485000   0.000000  12.485000 ( 12.635404)
jorg_w_mittag         16.968000   0.000000  16.968000 ( 17.080315)
jorg_w_mittag_2       11.828000   0.000000  11.828000 ( 11.935078)
stefan                10.766000   0.000000  10.766000 ( 10.831517)
stefanpochmann         9.734000   0.000000   9.734000 (  9.765227)
stefanpochmann 2       8.219000   0.000000   8.219000 (  8.240854)

我的基准代码:

require 'benchmark'

string = 'ruby'
@n = 10**7

Benchmark.bm(20) do |x|
  @x = x
  def report(name, &block)
    @x.report(name) {
      @n.times(&block)
    }
  end
  report('toro2k') {
    string.size.times.collect { |i| string[0..i] }
  }
  report('marek_lipka') {
    (0...(string.length)).map{ |i| string[0..i] }
  }
  report('jorg_w_mittag') {
    string.chars.inject([[], '']) { |(res, memo), c| 
      [res << memo += c, memo] 
    }.first
  }
  report('jorg_w_mittag_2') {
    acc = ''
    string.chars.map {|c| acc += c }
  }
  report('stefan') {
    Array.new(string.size) { |i| string[0..i] }
  }
  report('stefanpochmann') {
    (1..string.size).map { |i| string[0, i] }
  }
  report('stefanpochmann 2') {
    Array.new(string.size) { |i| string[0, i+1] }
  }
end
于 2017-12-10T13:58:24.190 回答