0

我已经返回一个三元运算符来检索和索引如下

val = (
  (@str_value.index("APPLE")).nil ? (
    (@str_value.index("DIAMOND")).nil ? @str_value.index("GARLIC") : str_value.index("DIAMOND")
  ) : @str_value.index("APPLE")
)

但是当我运行它时,它给了我一个错误。

undefined method `nil' for nil:NilClass

我是红宝石的新手。什么可能出错?

4

4 回答 4

7

基准时间:

require 'benchmark'

def amit_kumar_gupta(str_value)
  str_value.index("APPLE") || str_value.index("DIAMOND") || str_value.index("GARLIC")
end

def priti(str_value)
  %w(APPLE DIAMOND GARLIC).map{|i| str_value.index(i)}.compact[0]
end

def borodin(str_value)
  /APPLE|DIAMOND|GARLIC/ =~ str_value
end

# I added a single anchor, based on knowledge of where the target would be, to
# show the difference an anchored search can make.

def borodin2(str_value)
  str_value[/\b (?:APPLE|DIAMOND|GARLIC) \b\Z/x]
end

STRING = ('a'..'z').to_a.join * 100
APPLE_STRING = STRING + ' APPLE'
GARLIC_STRING = STRING + ' GARLIC'
N = 100_000

puts "RUBY_VERSION = #{ RUBY_VERSION }"
puts "N = #{N}"
Benchmark.bm(15) do |b|
  b.report('amit apple') { N.times { amit_kumar_gupta(APPLE_STRING) } }
  b.report('amit garlic') { N.times { amit_kumar_gupta(GARLIC_STRING) } }
  b.report('priti apple') { N.times { priti(APPLE_STRING) } }
  b.report('priti garlic') { N.times { priti(GARLIC_STRING) } }
  b.report('borodin apple') { N.times { borodin(APPLE_STRING) } }
  b.report('borodin garlic') { N.times { borodin(GARLIC_STRING) } }
  b.report('borodin2 apple') { N.times { borodin2(APPLE_STRING) } }
  b.report('borodin2 garlic') { N.times { borodin2(GARLIC_STRING) } }
end

1.9.3 的结果:

RUBY_VERSION = 1.9.3
N = 100000
                      user     system      total        real
amit apple        0.540000   0.000000   0.540000 (  0.539550)
amit garlic       1.560000   0.000000   1.560000 (  1.567501)
priti apple       1.670000   0.000000   1.670000 (  1.673736)
priti garlic      1.630000   0.000000   1.630000 (  1.630529)
borodin apple     0.810000   0.010000   0.820000 (  0.811853)
borodin garlic    0.810000   0.000000   0.810000 (  0.817202)
borodin2 apple    0.220000   0.000000   0.220000 (  0.223292)
borodin2 garlic   0.230000   0.000000   0.230000 (  0.225041)

和 Ruby 2.0.0-p195:

RUBY_VERSION = 2.0.0
N = 100000
                      user     system      total        real
amit apple        0.250000   0.000000   0.250000 (  0.253446)
amit garlic       0.730000   0.000000   0.730000 (  0.730139)
priti apple       0.820000   0.000000   0.820000 (  0.825674)
priti garlic      0.820000   0.010000   0.830000 (  0.821391)
borodin apple     2.230000   0.000000   2.230000 (  2.240345)
borodin garlic    2.250000   0.010000   2.260000 (  2.264021)
borodin2 apple    0.200000   0.000000   0.200000 (  0.197568)
borodin2 garlic   0.190000   0.000000   0.190000 (  0.197615)

我们学到了什么(多萝西)?:

Amit 的代码利用了||短路测试的优势。如果index("APPLE")找到该值,则不需要进一步测试并且处理停止。对于大型作业来说,这是一个巨大的时间和 CPU 节省。您可以看到必须搜索“APPLE”与“GARLIC”之间的差异的效果。第一个测试后返回,第二个测试后返回。

Priti's 强制所有测试,无论第一个或第二个是否找到答案,然后丢弃失败的结果。这是一个幼稚的尝试,而不是如何编写这种代码。

Borodin 的代码展示了如何简洁地测试一大堆不同的字符串,但是正则表达式有很多开销可以减慢它们的速度。有趣的是,v2.0-p195 比 1.9.3 慢得多。我不知道这是一个错误还是什么,但这很重要。在borodin2代码中,我还展示了如何捕获完整的单词,而不仅仅是子字符串。这在进行文本处理时非常重要,并且在您不使用正则表达式时变得更加困难。如果您追求整个单词,那么在我看来,正则表达式是唯一的方法。

我添加了borodin2测试并添加了一个“行尾”锚点,以显示关于字符串结构的一点点知识是多么重要。使用rindex而不是也index可以改善前四个测试,并且在所有情况下,如果目标字符串位于搜索字符串的前面,它们都会降级。这种先验知识很重要。扫描您的数据并了解您正在寻找什么,如果您能找到可以利用的模式,那么您的代码可以运行得更快。

在我看来,由于短路,Amit 的代码是最好的通用代码。Borodin 的代码是最容易扩展的,并且在 1.9.3 中速度更快,但在 2.0 中它很痛苦。就个人而言,我会使用borodinborodin2假设他们会弄清楚是什么在另一个 Ruby 版本中减慢了速度,但是 YMMV。我的机器上的 2.0.0-p195 和 2.0.0-p247 几乎没有区别,所以我没有展示它的结果。而且,也许这是我的模式中的一个缺陷,一个真正聪明的 Ruby 人会插话来纠正它。


修改代码以使用 Fruity:

require 'fruity'

def amit_kumar_gupta(str_value)
  str_value.index("APPLE") || str_value.index("DIAMOND") || str_value.index("GARLIC")
end

def priti(str_value)
  %w(APPLE DIAMOND GARLIC).map{|i| str_value.index(i)}.compact[0]
end

def borodin(str_value)
  /APPLE|DIAMOND|GARLIC/ =~ str_value
end

# I added a single anchor, based on knowledge of where the target would be, to
# show the difference an anchored search can make.

def borodin2(str_value)
  str_value[/\b (?:APPLE|DIAMOND|GARLIC) \b\Z/x]
end

STRING = ('a'..'z').to_a.join * 100
APPLE_STRING = STRING + ' APPLE'
GARLIC_STRING = STRING + ' GARLIC'

puts "RUBY_VERSION = #{ RUBY_VERSION }"
compare do
  amit_apple        { amit_kumar_gupta(APPLE_STRING)  }  
  amit_garlic       { amit_kumar_gupta(GARLIC_STRING) } 
  priti_apple       { priti(APPLE_STRING)             }             
  priti_garlic      { priti(GARLIC_STRING)            }            
  borodin_apple     { borodin(APPLE_STRING)           }           
  borodin_garlic    { borodin(GARLIC_STRING)          }          
  borodin2_apple    { borodin2(APPLE_STRING)          }          
  borodin2_garlic   { borodin2(GARLIC_STRING)         }         
end

RUBY_VERSION = 2.1.0
Running each test 4096 times. Test will take about 6 seconds.
amit_apple is faster than amit_garlic by 2.6x ± 0.1
amit_garlic is faster than borodin2_garlic by 10.000000000000009% ± 1.0% (results differ: 2601 vs GARLIC)
borodin2_garlic is similar to borodin2_apple (results differ: GARLIC vs APPLE)
borodin2_apple is faster than priti_apple by 39.99999999999999% ± 1.0% (results differ: APPLE vs 2601)
priti_apple is similar to priti_garlic
priti_garlic is faster than borodin_apple by 10x ± 0.1
borodin_apple is faster than borodin_garlic by 2.0000000000000018% ± 1.0%

回报:

RUBY_VERSION = 2.1.0
运行每个测试 4096 次。测试大约需要 6 秒。
amit_apple 比 amit_garlic 快 2.6x ± 0.1
amit_garlic 比 borodin2_garlic 快 10.000000000000009% ± 1.0%(结果不同:2601 vs GARLIC)
borodin2_garlic 与 borodin2_apple 相似(结果不同:GARLIC vs APPLE)
borodin2_apple 比 priti_apple 快 39.99999999999999% ± 1.0%(结果不同:APPLE vs 2601)
priti_apple 类似于 priti_garlic
priti_garlic 比 borodin_apple 快 10 倍 ± 0.1
borodin_apple 比 borodin_garlic 快 2.0000000000000018% ± 1.0%
于 2013-06-28T15:13:40.783 回答
4
@str_value.index("APPLE") || @str_value.index("DIAMOND") || @str_value.index("GARLIC")
于 2013-06-28T06:58:58.917 回答
3

简单地

val = /APPLE|DIAMOND|GARLIC/ =~ @str_value
于 2013-06-28T08:13:51.147 回答
2

String#index

返回给定子字符串或模式 (regexp) 在 str 中第一次出现的索引。如果未找到,则返回 nil。如果存在第二个参数,它指定字符串中开始搜索的位置。

改为使用@str_value.index("APPLE")).nil? ?

?你在这里错过了一个@str_value.index("APPLE")).nil ?

看到该nil对象有nil?方法而不是nil方法:

nil.methods.grep(/nil/)
# => [nil?]

所以你的表达方式是:

@str_value = "I love APPLE"
val = @str_value.index("APPLE") ? (@str_value.index("DIAMOND") ? @str_value.index("GARLIC") : @str_value.index("DIAMOND")) : @str_value.index("APPLE")
p val # => nil

更好的是:

@str_value = "I love APPLE"
%w(APPLE DIAMOND GARLIC).map{|i| @str_value.index(i)}.compact[0]
#>> 7
于 2013-06-28T06:54:18.813 回答