質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

Q&A

13回答

16289閲覧

「if, else, switch, for, while などの条件分岐やループ制御を使わないですむとコードが見やすくなる」

coke2

総合スコア17

C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

3グッド

5クリップ

投稿2016/03/30 06:43

「if, else, switch, for, while などの条件分岐やループ制御を使わないですむとコードが見やすくなる」
と耳にしました。

if elseの条件分岐はとても頻繁に使用しています。

string[] fruits = new {"apple", "strawberry", "orange"};

foreach(string fruit in fruits){
if (fruit.Contains("apple") || fruit.Contains("strawberry")
MessageBox.Show("color is red");
else if (fruit.Contains("orange")
MessageBox.Show("color is orange");
}

とかです。
これを条件分岐やループ制御なしで書くととってできますか?
もっと見やすいコードがあれば教えてください。

Tak1wa, arly_times👍を押しています

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答13

0

例えば以下とかどうぞ
State パターン
Javaですがオブジェクト指向としての考え方ですので同じです。

if や switch などの分岐なくしてプログラムは書けませんので、必ず使います。

ただ、ここはこれじゃダメだろーという部分はあります。
例えば、

C#

1switch(会員ランク) 2{ 3 case シルバー会員: 4 // シルバー会員用の金額計算 5 break; 6 7 case ゴールド会員: 8 // ゴールド会員用の金額計算 9 break; 10 11 default: 12 // 一般会員用の金額計算 13 break; 14}

プラチナ会員が増えた場合
ランクで分岐してるとこ全部洗い出さないとダメじゃないか。。。
おいおい・・・めちゃくちゃあるじゃねーか!・・・これ全部にcase足していくのかよ。。。
みたいになってきますので、
こういう場合は、Stateパターンを使うべきです。

C#

1GetMember().Rank.GetPrice(定価);

書かれている例で言うと、Fruitクラス作って、中で Color を持てば終わりのような気もします。

C#

1foreach(Fruit fruit in fruits){ 2 MessageBox.Show("color is " + fruit.Color); 3}

投稿2016/03/30 07:02

編集2016/03/30 07:32
root_jp

総合スコア4666

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

coke2

2016/03/30 07:21

ありがとうございます。 classいいですよね。
guest

0

9 年前になめらかなコードと名前をつけてみたものの、私以外には流行っていない用語のようです。
それはさておき、ポリモーフィズム自体が特異点を除去し、NUllObjectパターンなどの各種デザインパターンが特異点を除去し、オブジェクト指向以前からある特異点除去方法としてはテーブル化 (連想配列を使うといいよ、と他の回答にあるようなもの) や番兵なんかがあるわけです。
特異点がなくなると見通しがよくなり、潜在的なバグも減りますが、特異時の処理が隠れてしまい、一般的に抽象度が高まるので、慣れていないと逆に理解しにくくなってしまう懸念があります。

if や switch が少ないから読みやすい、というのは必ずしも真ではありませんが、読みづらい≈潜在的なバグの温床になっている≈メンテする気になれない、ようなコードは無駄に if や switch が多い、というのは(経験的に)真です。

あ、あと、たくさんコードを「読んで」、それなりにコードを書いていると、これは駄目だろうという if 文と、これは問題ないだろうという if 文の違いが感覚的にわかるようになってきます。

投稿2016/04/05 10:33

編集2016/04/05 11:56
unau

総合スコア2468

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

root_jp

2016/04/05 10:58

ベタベタのプログラムは、みんな文句を言っているものの、 一般的な技術者の水準から見た場合、実は一番分かりやすかったりしますからね。。。 抽象度が高まったオブジェクト指向のプログラムは、拡張性は高くなりますが、追いづらいのは間違いないです。 正確に追うには、それなりのスキルを要しますしね。 決して単なる技術オタクの自己満足にならないように、ある程度万人受けする、 妥協点を見つけて書ける人が、チームには必要だと思います。
unau

2016/04/05 11:51

異論ありません。 私の場合は、大学でも最初に就職した会社でも、言語自体を学ぶカリキュラムなどはない、すなわち、C 言語なら C 言語自体については知ってて当たり前、知らなきゃ自分で時間作って勉強しとけ、というのが当たり前、という最後の年代だったように感じます。言いたいこととしては、当時と今では「一般的な技術者の水準」がだいぶ違うのだろうな、という老人の繰り言なわけですが、世の中で必要とされているエンジニアの数が桁違いなので全体のレベルが下がるのは必然と言えば必然で。 私個人としては自分が使うものを自分で作るだけで、もはや誰かとチームを組んでコーディングすることもないでしょうから、思う存分技術オタクの自己満足をさせてもらっていますけれども。
guest

0

こんにちは。

「無駄な」条件分岐を書くことって意外にあるので、それを減らしましょうということではないでしょうか?
バグの主な原因の1つは条件分岐ミスですし。

例えば、a, bがbool型の時、

C#

1if (a && b) { 2 foo(); 3} 4if (!a && !b) { 5 foo(); 6}

よりは、

C#

1if (a == b) { 2 foo(); 3}

の方が良いと思います。
これはちょっと無理やりな例ですが、似たようなケースは身近に転がっていると思います。

投稿2016/03/30 07:28

Chironian

総合スコア23272

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

coke2

2016/03/31 00:43

こんにちは。おっしゃるとおりですね。不要な条件分岐が残っていたりするのは、定期的にrefacteringするといいなと思います。
guest

0

何事もそうですけど,「~だからこうした方がいい」というのはある意味正解で,ある意味ハズレだと思うんですよね

すでにたくさん回答があるのであれですけど,この回答群の中から好みの回答を選ぶのだってif ~ then ~ elseでしょうしね.

今回の命題の 「if, else, switch, for, while などの条件分岐やループ制御を使わないですむとコードが見やすくなる」なんてのもその通りで,

使わないでいいならそれに越したことはない

でしか無いと思うんです.

そのためにはコーディングの軽いうちに熟考し,あ,このケースがあるな,こんな感じでパターンが増えそうだな,どうやってまとめとこうかな?といった考え方を常に持つことが重要だと考えます.

たとえばroot_jpさんの解答の例に有る条件が増えたときの対処,なんていうのはすごくわかり易い例でして(+1させていただきました!),このようなケースは実に多くあります.

仕事柄工場の生産管理システムなどに携わっているのですが,品種の追加(新製品に対応するので,新しく生産する品物を増やしたい)なんてことがありますと,以前の品種コードをgrepし,そのコードに関連したところを片っ端から改造していく,なんてことをする羽目になっています(あ,これはベースのソフトの設計が悪くて泣かされているパターンです).

知識がある今ならばこんな風に設計して~,こんなクラスで実装して~,とか言えますけど,今更そんな改造は出来ないですね(動いているコードが正義,なんて皮肉もあります).

ですので,条件分岐やループ制御は自分の知識で十分理解できているところのみ省き,後は普通にコーディングする,というのがおすすめです(それが可読性が良い,ということです).

そもそも条件分岐やループ制御が自在にできるのがソフトウェアの強みです.
(ハードウェアで組まれたシーケンス制御なんてちょっと動作を変えるためにすげぇ改造が必要なんです…)

投稿2016/03/31 01:41

退会済みユーザー

退会済みユーザー

総合スコア0

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

coke2

2016/03/31 04:08

ほんとうです。とても実感こもっていて、共感しました。 いろいろ理解して、最適な方法を見つけたいです。
guest

0

root_jpさんが言われているstateパターンが定石だと思います。

今回の場合、if-elseなどによる条件分岐けが多いとき、もっと保守性や可読性、拡張性の高いコードにするにはどうしたら良いか…という古典的(で、多くの人が遭遇する)問題だと思います。
こういった問題の解決策というのは、多くの場合、先人の方々によってデザインパターンが既に考えだされていることが多いです。

結局、どれだけデザインパターンを理解して、使いこなせるかが、可読性のある(そして保守性、拡張性もある)コードを書く近道(もちろん命名規則やJavadocの書き方、リファクタリングの技術など色々他にも学ぶべきことはありますが。)だと思います。
デザインパターンについては、書籍などで体系的に一度学習されると良いと思います。

投稿2016/03/31 02:23

編集2016/03/31 02:26
Odacchi

総合スコア907

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

coke2

2016/03/31 04:13

そうですね。 みなさまにご回答いただいていて、感謝するとともに、これは古典的で典型的な質問なのだな、と認識しました。 classでifをなくせるというのは、今現在のわたしにはとてもvividなtopicで、重点的に身につけたいと考えているところです。 ちょっとステップアップできそうな、満開間近の春です。
guest

0

Stateパターンはおすすめの方法ですが、サンプルコードにはちょっと大げさかもと感じたので、ほかの方法を紹介します。

「if, else, switch, for, while などの条件分岐やループ制御を使わないですむとコードが見やすくなる」

と耳にしました。

私は、あまり同意できません。分岐が多くなるのはよくないコーディングの結果であって、分岐そのものを問題にするより、ネストが深い(C#の場合、中括弧の数が多い)が問題だと思います。

と言いつつ、ネストがのもよくないコーディングの結果だと思ってます。なぜネストが深くなってしまうのかというと、大きなことを一挙にやろうとしているからです。

それで、色の名前を判定するgetColorNameメソッドといろを表示するshoeColorメソッドを定義して下記のようなコードにしました。

C#

1using System; 2using System.Linq; 3 4public class Hello{ 5 public static void Main(){ 6 Func<string, string> getColorName = 7 fruit => { 8 if(fruit == "apple") return "red"; 9 if(fruit == "strawberry") return "red"; 10 if(fruit == "orange") return "orange"; 11 return "unknown color"; 12 }; 13 14 Action<string> showColor = 15 fruit => Console.WriteLine("Color is " + getColorName(fruit)); 16 17 string[] fruits = new string[]{"apple", "strawberry", "orange"}; 18 19 foreach(var fruit in fruits) showColor(fruit); 20 } 21}

特に見てほしいのは、getColorNameメソッドで、色を判定できたらすぐさまreturnをすることで、コードを単純化しています。メソッドを細かく分けることに慣れていない場合、すぐにreturnをするコードは不安になるとおもいますが、十分にメソッドの機能を小さくできていれば問題にはなりません。

HashTableやDictionaryがコードが単純だとは思います。今回はメソッドを分ける例を出したかったので、あえて使っていません。

投稿2016/04/05 10:33

iwamoto_takaaki

総合スコア2883

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

LiveScriptで書いてみました。
遷移先の画面で下記のコードを張り付けてrunボタンを押してみてくだしあ

fruits-colors = apple: \red strawberry: \red orange: \orange to-color = (name)-> fruits-colors.(name) or \nothing output-color = (fluits)-> fluits |> to-color |> -> console.log "color is #it" <[apple strawberry orange]> |> each output-color

私は英語力がないのであまり良い書き方は出来ませんが、
英語っぽく書いてみたり、関数型プログラミングを覚えると応用が効きやすいかとおもいます。
How to write a code like English(英文のようにプログラミングをする方法)

C#に応用出来るかはわかりませんが、
私はPHPのみでしたが、LiveScirtを業務で触るようになってからPHPのソースコードも影響うけてカラフルに書けるようになりました。
LiveScriptはマイナー過ぎるので、RubyやElixir、Haskellが良いかもしれません。。。

投稿2016/04/06 06:14

編集2016/04/06 08:32
miyabi-sun

総合スコア21158

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

時と場合と言語しだいじゃないスかねえ。
シンプルにするのと分かりやすいのとは違うと思うし。
// PHPですんませんが…
// if を使わない例として
// $fruit に果物の名前が入ってるとして
$ar = array("apple"=>"red", "strawberry"=>"red", "orange"=>"orange");
echo "color is " . $ar[$fruit];

ループなら高階関数が使えれば一行で済む場合もあるけど、
そういうコーディングに慣れてない人には難解ですしねえ。

投稿2016/03/30 07:07

takasima20

総合スコア7458

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

coke2

2016/03/30 07:18

ありがとうございます。 PHPも読めます。 やっぱりこんな風になりますね。
guest

0

この問題なら連想配列がいいと思います

Hashtable fruits = new Hashtable(); ht.Add("apple", "red"); ht.Add("strawberry", "red"); ht.Add("orange", "orange"); foreach(string fruit in fruits.Values){ MessageBox.Show("color is " + ht[fruit]); }

投稿2016/04/05 04:06

commabee

総合スコア38

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

Ç#でなくて C++ でのコードになりますが、
この場合は連想配列をつかうことで、条件分岐をなくすことができます。
くだものの種類がふえたり、その色の定義を変更するときに、一番変更量がすくないのは最後に示した方法です。
1.cpp

c++

1// g++ -std=c++11 1.cpp 2 3#include <iostream> 4#include <map> 5#include <string> 6using namespace std; 7 8int main() { 9 string fruits[] = {"apple", "strawberry", "orange"}; 10 11 // 質問文にあった方法 12 for(string fruit : fruits) { 13 cout << fruit << " "; 14 if (fruit == "apple" || fruit == "strawberry") { 15 cout << "color: red" << endl; 16 } else if (fruit == "orange") { 17 cout << "color: orange" << endl; 18 } 19 } 20 cout << endl; 21 22 // 連想配列をつかって条件分岐をなくした方法 その1 23 std::map<std::string, std::string> colors = { 24 {"apple", "red"}, {"strawberry", "red"}, {"orange", "orenge"}, 25 }; 26 for(string fruit : fruits) { 27 cout << fruit << " color: " << colors[fruit] << endl; 28 } 29 cout << endl; 30 31 // 連想配列をつかって条件分岐をなくした方法 その2 (colos だけを使う) 32 for (const auto &pair : colors) { 33 cout << pair.first << " color: " << pair.second << endl; 34 } 35 36 return 0; 37}

実行例

$g++ -std=c++11 1.cpp $ ./a.out apple color: red strawberry color: red orange color: orange apple color: red strawberry color: red orange color: orenge apple color: red orange color: orenge strawberry color: red

投稿2016/03/31 07:25

katoy

総合スコア22324

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

「if, else, switch, for, while などの条件分岐やループ制御を使わないですむとコードが見やすくなる」

条件分岐やループってのは構造化プログラミングで必須要素なので、まったく使わないというわけにはいかないでしょうが。。。

(new List<string> {"apple", "strawberry", "orange"}).ForEach( fruit => MessageBox.Show(fruit.Contains("orange")?"color is orange":"color is red") );

コレクションとラムダ式と3項演算子を組み合わせるとこんなものか。

投稿2016/03/30 07:03

編集2016/03/30 07:14
tkturbo

総合スコア5572

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

ozwk

2016/03/30 07:12

C#なら.ForEach()ですけどこれ言語は何ですか?
tkturbo

2016/03/30 07:19 編集

ForEachの誤りです。修正します。 # ちなみにC#です。
coke2

2016/03/30 07:21

ありがとうございます。 3項演算子は微妙な気がします。
guest

0

こういうのでしょうか?

C#

1using System; 2using System.Linq; 3using System.Collections.Generic; 4class Test 5{ 6 public static void Main(string[] args) 7 { 8 var fruits = new List<string> { 9 "fuji apple", 10 "wild strawberry", 11 "hassaku orange", 12 "forbidden fruit", 13 }; 14 var fruitColor = new Dictionary<string, string>() { 15 { "apple", "red" }, 16 { "strawberry", "red" }, 17 { "orange", "orange" }, 18 }; 19 fruits 20 .Select(fruit => fruitColor.FirstOrDefault(kv => fruit.Contains(kv.Key)).Value) 21 .Select(color => "color is "+ color) 22 .ToList() 23 .ForEach(str => Console.WriteLine(str)); 24 } 25}

これが「見やすい」かどうかは人それぞれだと思います。Linqや関数型プログラミングに慣れている人はこちらの方がより「見やすい」と感じるでしょうが、そうで無い人にとっては逆にわかりづらく思えるかも知れません。

この書き方は「見やすい」こと以外に利点があります。それは、「書き換えやすい」ことです。たとえば、新たに"lemon"について"yellow"を足したくなったとしましょう。if文の時は分岐を増やして、また同じ事を書く必要がありますが、こちらではfruitColorというDictionaryに{"lemon", "yellow"}を追加するだけで終わります。他にも、"color is ..."というところを"色は...です。"に書き換えたいとか、大文字小文字を無視したいとか、表示するのは最初の数個までにしたいとか、表示の方法を変えたいとかいうとき、ほとんどの場合が1行書き換えるか、追加するだけで済みます。

しかし、最初に言ったとおり、これはLinqや関数型プログラミングに慣れていることが前提です。慣れれば簡単ですが、慣れない内は難しいと感じるかと思いますので、全ての人に勧められるわけではありません。

投稿2016/04/06 15:32

編集2016/04/06 22:32
raccy

総合スコア21735

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

「見やすさ」と言うか、
この先の展開も考慮して考えます

このソースを見て、内容は、リストにある「リンゴ」や「オレンジ」に対して、
その色を表示するプログラムである
「リンゴ」や「ストロベリー」はリストにしている
リストにしていると言う事は、「この後このリストは増えるかもしれない」

さて、「この先、このリストが増えるかもしれない」と考えた時、
リストに項目が増える度に if 文の条件式を治す事になる
if (fruit.Contains("apple") || fruit.Contains("strawberry")
こういう式は避けた方が良いと判断します。

つまり、
フルーツのリストを作るのであれば、
色のリストも合わせて作った方がこの先の展開を考えた場合見やすくなる

だって、
if (fruit.Contains("apple") || fruit.Contains("strawberry")
この後に、 || fruit.Contains(赤い果物) が、永遠と並ぶ事を考えて
みたら判るでしょ

投稿2016/04/19 00:59

nak777

総合スコア12

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問