为什么检查 hash[key] 是否设置为 true(布尔)值的 if 条件不能按预期工作?

1 ruby hash nested

我有以下名为 cars 的嵌套哈希

{:honda=>{year=>2008,is_condition_good?=>true},
 :toyota=>{year=>2010,is_condition_good?=>false}
}
Run Code Online (Sandbox Code Playgroud)

我想返回满足 的嵌套哈希is_condition_good? = true。我意识到我可以使用 select 方法cars.select {|car, attributes| attributes[:is_condition_good?]=true},但以下代码似乎也应该有效,但由于某种原因,它不会进入 if 语句循环。我究竟做错了什么?

cars.each do |car, attributes|
  if attributes[:is_condition_good?] == true then
     return attributes
  end
end
Run Code Online (Sandbox Code Playgroud)

attributes[:is_condition_good?]之前打印过cars.each do |car, attributes|,看到它打印了true or false ,而且确实打印了。

Car*_*and 7

你建议写:

cars = {
  :honda =>{ year => 2008, is_condition_good? => true },
  :toyota=>{ year => 2010, is_condition_good? => false }
}
Run Code Online (Sandbox Code Playgroud)

当 Ruby 到达year(既不是字符串也不是符号)时,她将如何解析它。她会得出结论,这一定是变量或方法的名称。当她发现不存在具有该名称的变量或方法时,她将引发异常。

同样,如果 Ruby 在解析 时尚未引发异常findis_condition_good?则会出现相同的问题,但由于问号,它不可能是变量。

我希望您希望这两个都是符号,在这种情况下您应该写:

cars = {
  :honda  => { :year => 2008, :is_condition_good? => true },
  :toyota => { :year => 2010, :is_condition_good? => false }
}
Run Code Online (Sandbox Code Playgroud)

或者可以表达(您的选择):

cars = {
  :honda  => { year: 2008, condition_good?: true },
  :toyota => { year: 2010, condition_good?: false }
} 
Run Code Online (Sandbox Code Playgroud)

或者

cars = {
  honda:  { year: 2008, condition_good?: true },
  toyota: { year: 2010, condition_good?: false }
} 
Run Code Online (Sandbox Code Playgroud)

现在考虑您的“循环”代码:

def doit(cars)
  cars.each do |car, attributes|
    puts "car = #{car}, attributes = #{attributes}"
    if attributes[:condition_good?] == true then
      return attributes
    end
  end
end
Run Code Online (Sandbox Code Playgroud)

我已将您的(修改后的)代码放入方法中,因为它包含一条return语句和一个从方法返回的语句。我还添加了一条puts语句(稍后删除)来显示块变量的值。

请注意,一旦找到状况良好的汽车,此方法就会返回。相比之下,使用select(您提到的)将为每辆状况良好的汽车返回一个包含一个元素的数组。

现在让我们执行doit

doit(cars) 
  #=> {:year=>2008, :condition_good?=>true}
Run Code Online (Sandbox Code Playgroud)

这显示:

car = honda, attributes = {:year=>2008, :condition_good?=>true}
Run Code Online (Sandbox Code Playgroud)

如果没有状况良好的汽车,nil就会被退回。


您可以使用Enumerable#find方法改进代码

def doit(cars)
  cars.find do |car, attributes|
    attributes[:condition_good?]
  end
end
Run Code Online (Sandbox Code Playgroud)

请注意,这不需要return声明。

由于attributes[:condition_good?]返回trueor false,它与以下相同:

attributes[:condition_good?] == true
Run Code Online (Sandbox Code Playgroud)

我们应该放弃这一点== true,以免其他红宝石可能会在我们背后窃笑,因为我们相信我们不知道这== true是多余的。

我们现在得到:

doit cars
  #=> [:honda, {:year=>2008, :condition_good?=>true}]
Run Code Online (Sandbox Code Playgroud)

握紧电话!:condition_good返回值为的键和值true。我们只想要值,所以我们需要写:

def doit(cars)
  cars.find do |car, attributes|
    attributes[:condition_good?]
  end.last
end
Run Code Online (Sandbox Code Playgroud)
doit cars
  #=> {:year=>2008, :condition_good?=>true}
Run Code Online (Sandbox Code Playgroud)

这里.last取出最后一个元素

[:honda, {:year=>2008, :condition_good?=>true}]
Run Code Online (Sandbox Code Playgroud)

如果您认为这有点丑陋,那么您并不孤单。


有很多方法可以组织这些计算。我可能会这样做。

def doit(cars)
  cars.each_key.find { |name| cars[name][:condition_good?] }
end
Run Code Online (Sandbox Code Playgroud)
car = doit(cars)
  #=> :honda
Run Code Online (Sandbox Code Playgroud)

此时,我可以从以下位置提取我需要的任何信息:

attributes = cars[:honda]
  #=> {:year=>2008, :condition_good?=>true}
Run Code Online (Sandbox Code Playgroud)

请参阅哈希#each_key