各 'when'ブロックに複数の値を持つCaseステートメント


314

私が探しているものを説明できる最善の方法は、これまでに試した失敗したコードを示すことです。

case car
  when ['honda', 'acura'].include?(car)
    # code
  when 'toyota' || 'lexus'
    # code
end

when考えられる約50の異なるの値によって引き起こされる4つか5つの異なる状況がありますcarcaseブロックでこれを行う方法はありますか、または大規模なifブロックを試す必要がありますか?

回答:


669

case声明、,のと同じです||if声明。

case car
   when 'toyota', 'lexus'
      # code
end

Rubyのcaseステートメントでできるその他のこと


1
このリンクには、Rubyのcaseステートメントのより良い要約があります(正規表現とsplat構文の例も含まれています)。
rsenna

理由はわかりませんが、この奇妙な状況が発生します。これを書いた場合:when "toyota", "lexus"、次のようになりますunexpected tSTRING_BEG, expecting keyword_do or '{' or '(' (SyntaxError)。しかし、私がこれを書いた場合when "toyota","lexus"、それは機能します。唯一の違いは、コンマの後のスペースです。
Furkan Ayhan 2014年

@FurkanAyhan変ですね。私は先に進んで、コードテストして、それが機能することを確認しました。私の推測では、コードで他に何かが起こって、そのようなエラーが発生しているのでしょう。文字列をどこかで閉じるのを忘れた可能性はありますか?
Charles Caldwell

1
まあ、これは機能しますが、ルビーはプログラマーの使いやすさに重点を置いているので、なぜ標準をサポートしないのでしょうか。または「または」?これはちょっと混乱しています
Zia Ul Rehman Mughal 2017

2
Rubyは、orまたはをサポートしていません。||なぜなら、whenは単一の識別子ではなく、その右側に一連のコンマ区切りの式をとるからです。このため、があった場合when a or b、これをwhen a, bor when (a or b)と同等と見なすかどうかは不明です。 後者は、式をa or bwhenにスローする前に、最初に式を評価します。言語がコンテキストに基づいて動作を変更するトークンを持つことは、より意外で扱いにくいためor、whenの右側で実際の式を使用することはできません。
Taywee 2018

99

rubyの「splat」またはフラット化構文を利用できます。

これは、生い茂ったwhen句になります—私が正しく理解していれば、ブランチごとにテストする値が約10あります—私の意見では少し読みやすくなっています。さらに、実行時にテストする値を変更できます。例えば:

honda  = ['honda', 'acura', 'civic', 'element', 'fit', ...]
toyota = ['toyota', 'lexus', 'tercel', 'rx', 'yaris', ...]
...

if include_concept_cars
  honda += ['ev-ster', 'concept c', 'concept s', ...]
  ...
end

case car
when *toyota
  # Do something for Toyota cars
when *honda
  # Do something for Honda cars
...
end

もう1つの一般的なアプローチは、ハッシュをディスパッチテーブルとして使用することです。各値のキーとcar、実行するコードをカプセル化する呼び出し可能なオブジェクトである値を使用します。


これは私が最終的に使用したものですが、誰かのチェックマークを取り除くのは気分が悪いです:D
ニック

長いwhenラインのための素晴らしいソリューション。共有いただきありがとうございます。
ピストス2016

0

ロジックをデータに入れるもう1つの方法は、次のようなものです。

# Initialization.
CAR_TYPES = {
  foo_type: ['honda', 'acura', 'mercedes'],
  bar_type: ['toyota', 'lexus']
  # More...
}
@type_for_name = {}
CAR_TYPES.each { |type, names| names.each { |name| @type_for_name[type] = name } }

case @type_for_name[car]
when :foo_type
  # do foo things
when :bar_type
  # do bar things
end

失礼なことをするつもりはありませんが、時間と空間の両方で効率が悪いため、反対票を投じました。また、他の2つの回答よりも複雑で読みにくくなります。この方法を使用する利点は何ですか?
Nick

分類全体を1つのオブジェクトに入れます。これで、オブジェクトをシリアル化して他の人に送信してロジックを説明したり、データベースに保存して他のユーザーが編集できるようにするなど、そのオブジェクトを使用して処理を行うことができます。(新しい車のモデルが出るとすぐにロジックが変わりますよね?)あなたは「テーブル駆動」を調べるかもしれません。
Hew Wolff

YAGNI(「あなたはそれを必要としない」)はここで適用できます。この設計は、将来存在する可能性があるがまだ存在しないシナリオの時間/スペース効率と可読性を犠牲にします。コストは今支払われますが、報酬は決して得られないかもしれません。
Nick
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.