是否可以使用范围作为Ruby中哈希的键?

时间:2013-07-08 19:14:52

标签: ruby hash range

我正在尝试创建一个脚本来浏览索引,查看每个页码,然后告诉我该条目的书的哪一章。这是我正在做的事情的近似值:

@chapters = {
  1 => "introduction.xhtml",
  2..5 => "chapter1.xhtml",
  6..10 => "chapter2.xhtml",
  11..18 => "chapter3.xhtml",
  19..30 => "chapter4.xhtml" }

def find_chapter(number)
  @chapters.each do |page_range, chapter_name|
    if number === page_range
      puts "<a href=\"" + chapter_name + "\page" + number.to_s + "\">" + number.to_s + </a>"
    end
  end
end

find_chapter(1)将吐出我想要的字符串,但find_chapter(15)不会返回任何内容。是不是可以像这样使用范围?

6 个答案:

答案 0 :(得分:25)

您可以使用哈希键的范围,您可以使用select这样轻松查找键:

@chapters = { 1 => "introduction.xhtml", 2..5 => "chapter1.xhtml", 
              6..10 => "chapter2.xhtml", 11..18 => "chapter3.xhtml",                                         
              19..30 => "chapter4.xhtml" } 

@chapters.select {|chapter| chapter === 5 }
 #=> {2..5=>"chapter1.xhtml"} 

如果您只想要章节名称,只需添加.values.first,如下所示:

@chapters.select {|chapter| chapter === 9 }.values.first
 #=> "chapter2.xhtml" 

答案 1 :(得分:7)

当然,只需反转比较

if page_range === number

喜欢这个

@chapters = {
  1 => "introduction.xhtml",
  2..5 => "chapter1.xhtml",
  6..10 => "chapter2.xhtml",
  11..18 => "chapter3.xhtml",
  19..30 => "chapter4.xhtml" }

def find_chapter(number)
  @chapters.each do |page_range, chapter_name|
    if page_range === number
      puts chapter_name
    end
  end
end

find_chapter(1)
find_chapter(15)
# >> introduction.xhtml
# >> chapter3.xhtml

它的工作方式是这样的,因为Range上的===方法具有特殊行为:Range#===。如果您先放置number,则会调用Fixnum#===,它会以数字方式比较值。范围不是数字,因此它们不匹配。

答案 2 :(得分:5)

正如@Sergio Tulentsev所示,它可以完成。然而,通常的方法是使用case when。它更灵活,因为您可以在then子句中执行代码,并且可以使用else部分处理未处理的所有内容。它使用相同的===方法。

def find_chapter(number)
  title = case number
    when 1      then "introduction.xhtml"
    when 2..5   then "chapter1.xhtml"
    when 6..10  then "chapter2.xhtml"
    when 11..18 then "chapter3.xhtml"
    when 19..30 then "chapter4.xhtml"
    else "chapter unknown"
  end
  #optionally: do something with title
end

答案 3 :(得分:4)

这是一种简单的方法,只返回第一个匹配键的值:

# setup
i = 17; 
hash = { 1..10 => :a, 11..20 => :b, 21..30 => :c }; 

# find key
hash.find { |k, v| break v if k.cover? i }

答案 4 :(得分:1)

在此topic找到论坛。他们建议

class RangedHash
  def initialize(hash)
    @ranges = hash
  end

  def [](key)
    @ranges.each do |range, value|
      return value if range.include?(key)
    end
    nil
  end
end

现在您可以像

一样使用它
ranges = RangedHash.new(
  1..10 => 'low',
  21..30 => 'medium',
  41..50 => 'high'
)
ranges[5]  #=> "low"
ranges[15] #=> nil
ranges[25] #=> "medium"

答案 5 :(得分:1)

试试这个:

def find_chapter(page_number)
  @chapters.select{ |chapters_key| chapters_key === page_number.to_i}.values.first
end

然后你就这样称呼它:

find_chapter(10)
=> "chapter2.xhtml"


find_chapter(40)
=> nil