【问题标题】:ruby program with list带有列表的红宝石程序
【发布时间】:2016-11-26 15:21:16
【问题描述】:

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

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

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

但输出是这样的

红绿紫白

有人知道为什么吗?

【问题讨论】:

  • 因为您正在打印所有在蓝色之后按字母顺序排列的项目
  • 为什么不使用索引?
  • 谢谢。 davidhu2000

标签: arrays ruby


【解决方案1】:

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) 的解决方案几乎和 test/variable 一样快。

免责声明:对于更快的解决方案,我没有太多想法。所以也许有更有效的方法。感谢 dogbert 的提示。

【讨论】:

  • “无索引”要求很可能来自练习,而不是来自性能瓶颈。
  • 谢谢。你的回答很足智多谋。
  • 如果您将Array#index 调用移到.each_with_index 块之外,您将获得巨大的加速。现在这个实现是O(n^2),如果你把它移出来,那就是O(n)。 (但它仍然比第一个实现慢,因为它必须遍历数组两次。)
  • @Dogbert 谢谢。我已将您的提案添加到基准测试中。
【解决方案2】:

另一个与@knut 的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 &lt; 1 是一个保护子句,如果target 不是arr 中的元素,则防止无限循环。

【讨论】:

  • 我喜欢数组复制的想法。在重复使用的情况下,您将不再需要检查。我没有得到``的原因。你能解释一下为什么需要它吗?至少你还需要一个after_blue.each{|item| print item } 来给出结果。
  • 看起来像一个乱码传输,不知道你在问什么,因为我没有任何反引号。完成后,after_blue 数组仅包含“蓝色”条目之后的那些元素,您可以随心所欲地对它们进行任何操作。
  • 抱歉,有些零件丢失了。我没有得到|| after_blue.length &lt; 1的原因
  • @knut 将其重写为方法,并添加了要求的解释作为答案的一部分。
【解决方案3】:

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

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)

【讨论】:

    猜你喜欢
    • 2010-12-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-10-19
    • 1970-01-01
    • 2016-02-15
    • 1970-01-01
    • 2019-08-09
    相关资源
    最近更新 更多