Techioz Blog

hash[key] が true (ブール値) の値に設定されているかどうかを確認する if 条件が期待どおりに機能しないのはなぜですか?

概要

車という名前の次のネストされたハッシュがあります

{:honda=>{year=>2008,is_condition_good?=>true},
 :toyota=>{year=>2010,is_condition_good?=>false}
}

is_condition_good?を満たすネストされたハッシュを返したいです。 =本当です。 select メソッド cars.select {|car,attributs| を使用できることに気付きました。 attributes[:is_condition_good?]=true} ただし、次のコードも同様に機能するように見えますが、何らかの理由で if ステートメントのループに入りません。私の何が間違っているのでしょうか?

cars.each do |car, attributes|
  if attributes[:is_condition_good?] == true then
     return attributes
  end
end

cars.each が |car,attributs| を実行する前に、attributes[:is_condition_good?] を出力しました。 true または false が出力され、実際に出力されたことを確認します。

解決策

あなたは次のように書くことを提案します。

cars = {
  :honda =>{ year => 2008, is_condition_good? => true },
  :toyota=>{ year => 2010, is_condition_good? => false }
}

Ruby は、年 (文字列でも記号でもありません) を取得したときに、これをどのように解析するでしょうか。彼女は、それは変数またはメソッドの名前に違いないと結論付けるでしょう。その名前の変数またはメソッドが存在しないことが判明すると、例外が発生します。

同様に、Ruby は find, is_condition_good を解析するときにまだ例外を発生させていませんでしたか?ただし、疑問符があるため、変数にすることはできません。

両方ともシンボルであることを意図していると思いますが、その場合は次のように記述する必要があります。

cars = {
  :honda  => { :year => 2008, :is_condition_good? => true },
  :toyota => { :year => 2010, :is_condition_good? => false }
}

これは、次のように表現することもできます (お好みで)。

cars = {
  :honda  => { year: 2008, condition_good?: true },
  :toyota => { year: 2010, condition_good?: false }
} 

または

cars = {
  honda:  { year: 2008, condition_good?: true },
  toyota: { year: 2010, condition_good?: false }
} 

次に、「ループ」コードを考えてみましょう。

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

コードには return ステートメントとメソッドからのリターンが含まれているため、(変更した) コードをメソッドに配置しました。ブロック変数の値を表示するために、puts ステートメント (後で削除されます) も追加しました。

このメソッドは、良好な状態の車が見つかるとすぐに返されることに注意してください。対照的に、select (あなたが言及した) を使用すると、良好な状態の車ごとに 1 つの要素を含む配列が返されます。

それでは doit を実行してみましょう。

doit(cars) 
  #=> {:year=>2008, :condition_good?=>true}

これにより、次のように表示されます。

car = honda, attributes = {:year=>2008, :condition_good?=>true}

良好な状態の車がなかったら、何も返されなかったでしょう。

Enumerable#find メソッドを使用してコードを改善できます。

def doit(cars)
  cars.find do |car, attributes|
    attributes[:condition_good?]
  end
end

これには return ステートメントが必要ないことに注意してください。

attributs[:condition_good?] は true または false を返すため、次と同じです。

attributes[:condition_good?] == true

== true は不要であることに気づいていないと他の Rubiest が陰で嘲笑しないように、== true を削除する必要があります。

これで以下が得られます。

doit cars
  #=> [:honda, {:year=>2008, :condition_good?=>true}]

電話を保留してください!これにより、値 :condition_good が true となるキーと値が返されました。値が必要なだけなので、次のように記述する必要があります。

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

ここで、 .last は次の最後の要素を取り出します。

[:honda, {:year=>2008, :condition_good?=>true}]

それはちょっと醜い、と思っているのはあなただけではありません。

これらの計算を整理する方法はたくさんあります。以下のようにすればいいかもしれません。

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

この時点で、必要な情報はすべて以下から抽出できます。

attributes = cars[:honda]
  #=> {:year=>2008, :condition_good?=>true}

「ハッシュ#each_key」を参照してください。