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

Tom*_*Tom 21 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
Run Code Online (Sandbox Code Playgroud)

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

fab*_*bbb 29

你可以使用一个范围的哈希键,你可以很容易地使用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"} 
Run Code Online (Sandbox Code Playgroud)

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

@chapters.select {|chapter| chapter === 9 }.values.first
 #=> "chapter2.xhtml" 
Run Code Online (Sandbox Code Playgroud)

  • 试试```@ chapters.detect {| k,v | k === 5} .last```因为,与select不同,detect将在第一次匹配时停止迭代. (14认同)

Ser*_*sev 7

当然,只需逆转比较

if page_range === number
Run Code Online (Sandbox Code Playgroud)

像这样

@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
Run Code Online (Sandbox Code Playgroud)

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


Noa*_*orp 6

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

# 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 }
Run Code Online (Sandbox Code Playgroud)


ste*_*lag 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
Run Code Online (Sandbox Code Playgroud)