带列表的ruby程序

时间:2016-11-26 15:21:16

标签: arrays ruby

我想在不使用索引的情况下获取颜色 blue 之后要打印的颜色列表。我这样做了

colors = ["Red", "Blue", "Green", "Purple", "White", "Black"]

colors.each { |item| print item if item > "Blue" }

但输出是

  

红绿紫白色

有谁知道为什么?

3 个答案:

答案 0 :(得分:4)

问题"为什么"已经在davidhu2000的评论中回答:

  

因为您打印的是蓝色后按字母顺序排列的所有项目

如果您不想使用索引,那么您可以使用带有帮助变量的解决方案:

colors = ["Red", "Blue", "Green", "Purple", "White", "Black"]

blue_found  = false
colors.each { |item| 
  if blue_found
    print item
  else
      blue_found ||= item == "Blue" 
  end
}

如果你喜欢单行,你可以使用

  blue_found ? (print item) :  (blue_found ||= item == "Blue" )

另一种可能性:

colors = ["Red", "Blue", "Green", "Purple", "White", "Black"]

blue_found  = false
colors.each { |item| 
  print item if blue_found 
  blue_found ||= item == "Blue" 
}

我很好奇,为什么你不想使用索引,所以我在你的问题之外做了一些研究。

带索引的解决方案是:

colors.each_with_index { |item,i| 
  print item if i > colors.index("Blue")
}

index - 方法可能需要更多运行时。为了测试它,我做了一个基准测试:

colors = ["Red", "Blue", "Green", "Purple", "White", "Black"]
require 'benchmark'

TEST_LOOPS = 100_000

def action(item)
  #Just a no-action.
end

Benchmark.bm(10) {|b|

  b.report('test/variable') {
   TEST_LOOPS.times { 
    blue_found  = false
    colors.each { |item| 
      action(item) if blue_found 
      blue_found ||= item == "Blue" 
    }
   }            #Testloops
  }             #b.report

  b.report('test/index') {
   TEST_LOOPS.times { 
    colors.each_with_index { |item,i| 
      action(item) if i > colors.index("Blue")
    }
   }            #Testloops
  }             #b.report

  b.report('test/index2') {
   TEST_LOOPS.times { 
    index_blue = colors.index("Blue")
    colors.each_with_index { |item,i| 
      action(item) if i > index_blue
    }
   }            #Testloops
  }             #b.report

  b.report('test/dogbert') {
   TEST_LOOPS.times { 
      # Drop all items until you find "Blue", then drop the "Blue".
      colors.drop_while { |item| item != "Blue" }.drop(1).each do |item|
        action(item)
      end
    }            #Testloops
  }             #b.report

  b.report('test/pjs') {
   TEST_LOOPS.times { 
      after_blue = colors.dup
      loop do
        break if after_blue.shift == 'Blue'|| after_blue.length < 1
      end
      after_blue.each{|item| action(item) }
   }            #Testloops
  }             #b.report

} #Benchmark

结果:

                 user     system      total        real
test/variable  0.187000   0.000000   0.187000 (  0.179010)
test/index     0.250000   0.000000   0.250000 (  0.254015)
test/index2    0.140000   0.000000   0.140000 (  0.136008)
test/dogbert   0.110000   0.000000   0.110000 (  0.111006)
test/pjs       0.327000   0.000000   0.327000 (  0.332019)

因此带有帮助变量的版本(正如预期的那样)更快。但是如果你在循环之外定义一次索引,那么带索引(test / index2)的解决方案几乎和测试/变量一样快。

免责声明:我对更快的解决方案没有多少想法。所以也许有一种更有效的方式。感谢dogbert的暗示。

答案 1 :(得分:2)

使用@ knut&#39; test/variable基准测试的另一种方法是:

def values_after(target, arr)
  result = arr.dup
  loop do
    break if result.shift == target || result.length < 1
  end
  result
end

colors = ['Red', 'Blue', 'Green', 'Purple', 'White', 'Black']
puts *values_after('Blue', colors)
# Or, if you prefer all on one comma-separated line:
#   puts values_after('Blue', colors).join(', ')

如果|| result.length < 1不是target中的元素,则arr是一个防止无限循环的保护子句。

答案 2 :(得分:0)

虽然已经出现的两个答案给出了正确的答案,但我会使用更具功能性的风格,在我看来更具可读性。

colors = ["Red", "Blue", "Green", "Purple", "White", "Black"]
# Drop all items until you find "Blue", then drop the "Blue".
colors.drop_while { |item| item != "Blue" }.drop(1).each do |item|
  puts item
end

由于@knut提到了基准测试,这段代码只比@ knut的test/variable基准测试慢一点:

                 user     system      total        real
test/variable  0.790000   0.000000   0.790000 (  0.790960)
test/drop      0.900000   0.000000   0.900000 (  0.898137)