C#サンプル問題に基礎から応用を適用してみる
サンプル問題
次の5つの整数で、最大(MAX)のもの、最小(MIN)のもの、また平均値を表示するプログラムを作りましょう。
4 5 2 7 1
表示結果サンプル
DATA = 4 5 2 7 1 最大(MAX) = 7 最小(MIN) = 1 平均値(AVERAGE) = 3.8
解答方法1(変数とif文)
元になる変数
宣言
まず、プログラムで使う変数を整数型で宣言しましょう
int num1; int num2; int num3; int num4; int num5;
代入
次にそれぞれの変数に整数値を代入します。
num1 = 4; num2 = 5; num3 = 2; num4 = 7; num5 = 1;
データを一覧表示する
Console.WriteLine($"DATA = {num1} {num2} {num3} {num4} {num5}");
最大値の計算
最大値を入れておく変数の宣言の宣言
// 最大値を入れておく変数 int max;
初期値0の代入
// 最初に0を代入しておく max = 0;
計算式
もし、1つ目の数がmaxより大きかったらmaxを置き換える
最初はmaxが0でnum1が4なので、maxは4になる
if (num1 > max) { max = num1; }
他のデータについても同様に繰り返す
if (num1 > max) { max = num1; } if (num2 > max) { max = num2; } if (num3 > max) { max = num3; } if (num4 > max) { max = num4; } if (num5 > max) { max = num5; }
最小値の計算
最小値を入れておく変数の宣言の宣言
// 最小値を入れておく変数 int min;
初期値1000(十分大きな値として)の代入
// 最初に1000を代入しておく min = 0;
計算式
もし、1つ目の数がminより小さかったらminを置き換える
最初はminが1000でnum1が4なので、minは4になる
if (num1 < min) { min = num1; }
他のデータについても同様に繰り返す
if (num1 < min) { min = num1; } if (num2 < min) { min = num2; } if (num3 < min) { min = num3; } if (num4 < min) { min = num4; } if (num5 < min) { min = num5; }
結果を表示する
Console.WriteLine($"最小(MIN) = {min}");
平均値の計算
平均値を入れておく変数の宣言の宣言
// 最小値を入れておく変数 float average;
計算式
全ての値を足し算して要素の数で割ります。
average = sum / 5.0f;
結果を表示する
Console.WriteLine($"平均値(AVERAGE) = {average}");
ここまでの表示結果
結果は期待通りになりました。
DATA = 4 5 2 7 1 最大(MAX) = 7 最小(MIN) = 1 平均値(AVERAGE) = 3.8
コード一覧
動作はしていますが、残念な点があります
- 元のデータを増やすと多くの変更箇所が発生する
- 元のデータを減らしても同じく多くの変更箇所が発生する
- Mainメソッドがすでに100行近くになり、見づらい
これを100個の数字で計算してくださいと言われると、もうお手上げですね。
using System; namespace BasicToevelopment { class Program { static void Main(string[] args) { int num1; int num2; int num3; int num4; int num5; num1 = 4; num2 = 5; num3 = 2; num4 = 7; num5 = 1; Console.WriteLine($"DATA = {num1} {num2} {num3} {num4} {num5}"); int max; max = 0; if (num1 > max) { max = num1; } if (num2 > max) { max = num2; } if (num3 > max) { max = num3; } if (num4 > max) { max = num4; } if (num5 > max) { max = num5; } Console.WriteLine($"最大(MAX) = {max}"); int min; min = 1000; if (num1 < min) { min = num1; } if (num2 < min) { min = num2; } if (num3 < min) { min = num3; } if (num4 < min) { min = num4; } if (num5 < min) { min = num5; } Console.WriteLine($"最小(MIN) = {min}"); int sum = num1 + num2 + num3 + num4 + num5; float average; average = sum / 5.0f; Console.WriteLine($"平均値(AVERAGE) = {average}"); } } }
コード一覧(リファクタリング後)
変数の宣言と代入を1行にまとめましょう。
コードの見易さは、損なわれずに10行ほど短くなりました。
ただ、まだ要素数の増減については対応できていないです。
using System; namespace BasicToevelopment { class Program { static void Main(string[] args) { int num1 = 4; int num2 = 5; int num3 = 2; int num4 = 7; int num5 = 1; Console.WriteLine($"DATA = {num1} {num2} {num3} {num4} {num5}"); int max = 0; if (num1 > max) { max = num1; } if (num2 > max) { max = num2; } if (num3 > max) { max = num3; } if (num4 > max) { max = num4; } if (num5 > max) { max = num5; } Console.WriteLine($"最大(MAX) = {max}"); int min = 1000; if (num1 < min) { min = num1; } if (num2 < min) { min = num2; } if (num3 < min) { min = num3; } if (num4 < min) { min = num4; } if (num5 < min) { min = num5; } Console.WriteLine($"最小(MIN) = {min}"); int sum = num1 + num2 + num3 + num4 + num5; float average = sum / 5.0f; Console.WriteLine($"平均値(AVERAGE) = {average}"); } } }
解答方法2(配列)
単純に置き換えてみる
using System; namespace BasicToevelopment { class Program { static void Main(string[] args) { int[] nums = new int[5]; nums[0] = 4; nums[1] = 5; nums[2] = 2; nums[3] = 7; nums[4] = 1; Console.WriteLine($"DATA = {nums[0]} {nums[1]} {nums[2]} {nums[3]} {nums[4]}"); int max = 0; if (nums[0] > max) { max = nums[0]; } if (nums[1] > max) { max = nums[1]; } if (nums[2] > max) { max = nums[2]; } if (nums[3] > max) { max = nums[3]; } if (nums[4] > max) { max = nums[4]; } Console.WriteLine($"最大(MAX) = {max}"); int min = 1000; if (nums[0] < min) { min = nums[0]; } if (nums[1] < min) { min = nums[1]; } if (nums[2] < min) { min = nums[2]; } if (nums[3] < min) { min = nums[3]; } if (nums[4] < min) { min = nums[4]; } Console.WriteLine($"最小(MIN) = {min}"); int sum = nums[0] + nums[1] + nums[2] + nums[3] + nums[4]; float average = sum / 5.0f; Console.WriteLine($"平均値(AVERAGE) = {average}"); } } }
最大値の計算が繰り返しになっているので、繰り返し文に置き換えてみる(For文)
using System; namespace BasicToevelopment { class Program { static void Main(string[] args) { int[] nums = new int[5]; nums[0] = 4; nums[1] = 5; nums[2] = 2; nums[3] = 7; nums[4] = 1; Console.WriteLine($"DATA = {nums[0]} {nums[1]} {nums[2]} {nums[3]} {nums[4]}"); int max = 0; for (int i = 0; i < 4; i++) { if (nums[i] > max) { max = nums[i]; } } Console.WriteLine($"最大(MAX) = {max}"); int min = 1000; if (nums[0] < min) { min = nums[0]; } if (nums[1] < min) { min = nums[1]; } if (nums[2] < min) { min = nums[2]; } if (nums[3] < min) { min = nums[3]; } if (nums[4] < min) { min = nums[4]; } Console.WriteLine($"最小(MIN) = {min}"); int sum = nums[0] + nums[1] + nums[2] + nums[3] + nums[4]; float average = sum / 5.0f; Console.WriteLine($"平均値(AVERAGE) = {average}"); } } }
続けて最小値も置き換えてみる(For文)
using System; namespace BasicToevelopment { class Program { static void Main(string[] args) { int[] nums = new int[5]; nums[0] = 4; nums[1] = 5; nums[2] = 2; nums[3] = 7; nums[4] = 1; Console.WriteLine($"DATA = {nums[0]} {nums[1]} {nums[2]} {nums[3]} {nums[4]}"); int max = 0; for (int i = 0; i < 4; i++) { if (nums[i] > max) { max = nums[i]; } } Console.WriteLine($"最大(MAX) = {max}"); int min = 1000; for (int i = 0; i < 4; i++) { if (nums[i] < min) { min = nums[i]; } } Console.WriteLine($"最小(MIN) = {min}"); int sum = nums[0] + nums[1] + nums[2] + nums[3] + nums[4]; float average = sum / 5.0f; Console.WriteLine($"平均値(AVERAGE) = {average}"); } } }
配列の初期値代入を省略化してみる
一気にコード行が減りました。(50行ほど削減されています。)
ずいぶんすっきりしてきました。
using System; namespace BasicToevelopment { class Program { static void Main(string[] args) { int[] nums = { 4, 5, 2, 7, 1 }; Console.WriteLine($"DATA = {nums[0]} {nums[1]} {nums[2]} {nums[3]} {nums[4]}"); int max = 0; for (int i = 0; i < 4; i++) { if (nums[i] > max) { max = nums[i]; } } Console.WriteLine($"最大(MAX) = {max}"); int min = 1000; for (int i = 0; i < 4; i++) { if (nums[i] < min) { min = nums[i]; } } Console.WriteLine($"最小(MIN) = {min}"); int sum = nums[0] + nums[1] + nums[2] + nums[3] + nums[4]; float average = sum / 5.0f; Console.WriteLine($"平均値(AVERAGE) = {average}"); } } }
要素の数が変更されても対応できるようにする
これまでのコードでは、要素数は固定でした。要素数は、要素数.Lengthで取得できるのでこれに置き換えます。また、最初のデータの表示部分もFor文に置き換えておきます。足し算をするコードもFor文で対応します。
using System; namespace BasicToevelopment { class Program { static void Main(string[] args) { int[] nums = { 4, 5, 2, 7, 1, 10 }; Console.Write($"DATA = "); for (int i = 0; i < nums.Length; i++) { Console.Write($"{nums[i]} "); } Console.WriteLine(); int max = 0; for (int i = 0; i < nums.Length; i++) { if (nums[i] > max) { max = nums[i]; } } Console.WriteLine($"最大(MAX) = {max}"); int min = 1000; for (int i = 0; i < nums.Length; i++) { if (nums[i] < min) { min = nums[i]; } } Console.WriteLine($"最小(MIN) = {min}"); int sum = 0; for (int i = 0; i < nums.Length; i++) { sum += nums[i]; } float average = (float)sum / nums.Length; Console.WriteLine($"平均値(AVERAGE) = {average}"); } } }
データを置き換えて確認してみましょう
int[] nums = { 4, 5, 2, 7, 1, 10 };
結果
DATA = 4 5 2 7 1 10 最大(MAX) = 10 最小(MIN) = 1 平均値(AVERAGE) = 4.833333
メソッドにする
最大値を求めるコードをメソッド化します。
次の部分になります。
int max = 0; for (int i = 0; i < nums.Length; i++) { if (nums[i] > max) { max = nums[i]; } }
VisualStudioのインテリセンスで自動的に作成できます。

作成後
Mainメソッド内
int max = Max(nums);
作られたメソッド
static int Max(int[] nums) { int max = 0; for (int i = 0; i < nums.Length; i++) { if (nums[i] > max) { max = nums[i]; } } return max; }
Mainメソッドから、Maxメソッドにデータ配列を渡して、結果をint型で返してもらいます。
Minメソッド、Averageメソッドも同様に作成します。
static int Min(int[] nums) { int min = 1000; for (int i = 0; i < nums.Length; i++) { if (nums[i] < min) { min = nums[i]; } } return min; }
static float Average(int[] nums) { int sum = 0; for (int i = 0; i < nums.Length; i++) { sum += nums[i]; } float average = (float)sum / nums.Length; return average; }
メインメソッドは次のようになります。
static void Main(string[] args) { int[] nums = { 4, 5, 2, 7, 1, 10 }; Console.Write($"DATA = "); for (int i = 0; i < nums.Length; i++) { Console.Write($"{nums[i]} "); } Console.WriteLine(); int max = Max(nums); Console.WriteLine($"最大(MAX) = {max}"); int min = Min(nums); Console.WriteLine($"最小(MIN) = {min}"); float average = Average(nums); Console.WriteLine($"平均値(AVERAGE) = {average}"); }
LINQを使う
MaxメソッドをLINQを使って置き換えます。
static int Max(int[] nums) { return nums.Max(); }
Minメソッド、Averageメソッドも置き換えます。
static int Min(int[] nums) { return nums.Min(); }
static float Average(int[] nums) { return (float)nums.Average(); }
タプルを使う
3つのメソッドをまとめて1つのメソッドにします。戻り値を複数返せるC#7から使えるタプルで作成します。
static (int max,int min,float average) MaxMixAverage(int[] nums) { return (nums.Max(), nums.Min(), (float)nums.Average()); }
Mainメソッドは次のように変更します。
(int max, int min, float average) = MaxMixAverage(nums);
さらに、メソッドから戻り値の型が推論できますので、
var (max, min, average) = MaxMixAverage(nums);
以上をまとめると、
using System; using System.Linq; namespace BasicToevelopment { class Program { static void Main(string[] args) { int[] nums = { 4, 5, 2, 7, 1, 10 }; Console.Write($"DATA = "); for (int i = 0; i < nums.Length; i++) { Console.Write($"{nums[i]} "); } Console.WriteLine(); var (max, min, average) = MaxMixAverage(nums); Console.WriteLine($"最大(MAX) = {max}"); Console.WriteLine($"最小(MIN) = {min}"); Console.WriteLine($"平均値(AVERAGE) = {average}"); } static (int max, int min, float average) MaxMixAverage(int[] nums) { return (nums.Max(), nums.Min(), (float)nums.Average()); } } }
メソッドを式本体にする
ここまでで十分ですが、さらにfor文を消して、メソッドを式本体にすると
using System; using System.Linq; namespace BasicToevelopment { class Program { static void Main(string[] args) { int[] nums = { 4, 5, 2, 7, 1, 10 }; Console.Write($"DATA = "); nums.ToList().ForEach(n => Console.Write($"{n} ")); Console.WriteLine(); var (max, min, average) = MaxMixAverage(nums); Console.WriteLine($"最大(MAX) = {max}"); Console.WriteLine($"最小(MIN) = {min}"); Console.WriteLine($"平均値(AVERAGE) = {average}"); } static (int max, int min, float average) MaxMixAverage(int[] nums) => (nums.Max(), nums.Min(), (float)nums.Average()); } }
処理結果は最初と同じです。コード行は1/3になりました。改行を除くと14行まで減っています。
さらにさらに、やりすぎを恐れずに書くと、Mainメソッドは4行まで減らすこともできます。
using System.Linq; using static System.Console; namespace BasicToevelopment { class Program { static void Main() { int[] nums = { 4, 5, 2, 7, 1, 10 }; Write($"DATA = "); nums.ToList().ForEach(n => Write($"{n} ")); Show(MaxMixAverage(nums)); } static (int max, int min, float average) MaxMixAverage(int[] nums) => (nums.Max(), nums.Min(), (float)nums.Average()); static void Show((int max, int min, float average) calc) { WriteLine(); WriteLine($"最大(MAX) = {calc.max}"); WriteLine($"最小(MIN) = {calc.min}"); WriteLine($"平均値(AVERAGE) = {calc.average}"); } } }
IEnumerable型に変更
List<> 型のデータでも使えるようにするため、配列、List<>両方が実装しているIEnumerable<> を引数にとるメソッドを追加します。
using System.Collections.Generic; using System.Linq; using static System.Console; namespace BasicToevelopment { class Program { static void Main() { IEnumerable<int> nums; nums = new[] { 4, 5, 2, 7, 1, 10 }; Run(nums); nums = new List<int> { 4, 5, 2, 7, 1, 10 }; Run(nums); } private static void Run(IEnumerable<int> nums) { Write($"DATA = "); nums.ToList().ForEach(n => Write($"{n} ")); Show(MaxMixAverage(nums)); } static (int max, int min, float average) MaxMixAverage(IEnumerable<int> nums) => (nums.Max(), nums.Min(), (float)nums.Average()); static void Show((int max, int min, float average) calc) { WriteLine(); WriteLine($"最大(MAX) = {calc.max}"); WriteLine($"最小(MIN) = {calc.min}"); WriteLine($"平均値(AVERAGE) = {calc.average}"); } } }
Dictionary型も追加してみると
using System.Collections.Generic; using System.Linq; using static System.Console; namespace BasicToevelopment { class Program { static void Main() { IEnumerable<int> nums; nums = new int[] { 4, 5, 2, 7, 1, 10 }; Run(nums); nums = new List<int> { 4, 5, 2, 7, 1, 10 }; Run(nums); nums = new Dictionary<int, int> { [2] = 4, [3] = 5, [6] = 2, [9] = 7, [1] = 1, [4] = 10 }.Values.ToList(); Run(nums); } private static void Run(IEnumerable<int> nums) { Write($"DATA = "); nums.ToList().ForEach(n => Write($"{n} ")); Show(MaxMixAverage(nums)); } static (int max, int min, float average) MaxMixAverage(IEnumerable<int> nums) => (nums.Max(), nums.Min(), (float)nums.Average()); static void Show((int max, int min, float average) calc) { WriteLine(); WriteLine($"最大(MAX) = {calc.max}"); WriteLine($"最小(MIN) = {calc.min}"); WriteLine($"平均値(AVERAGE) = {calc.average}"); } } }
引数に直接インスタンスを渡す(new)こともできます。
using System.Collections.Generic; using System.Linq; using static System.Console; namespace BasicToevelopment { class Program { static void Main() { Run(new[] { 4, 5, 2, 7, 1, 10 }); Run(new List<int> { 4, 5, 2, 7, 1, 10 }); Run(new Dictionary<int, int> { [2] = 4, [3] = 5, [6] = 2, [9] = 7, [1] = 1, [4] = 10 }.Values.ToList()); } private static void Run(IEnumerable<int> nums) { Write($"DATA = "); nums.ToList().ForEach(n => Write($"{n} ")); Show(MaxMixAverage(nums)); } static (int max, int min, float average) MaxMixAverage(IEnumerable<int> nums) => (nums.Max(), nums.Min(), (float)nums.Average()); static void Show((int max, int min, float average) calc) { WriteLine(); WriteLine($"最大(MAX) = {calc.max}"); WriteLine($"最小(MIN) = {calc.min}"); WriteLine($"平均値(AVERAGE) = {calc.average}"); } } }
コレクションの結合テスト
using System.Collections.Generic; using System.Linq; using static System.Console; namespace BasicToevelopment { class Program { static void Main() { IEnumerable<int> nums1, nums2, nums3; nums1 = new int[] { 4, 5, 2, 7, 1, 10 }; nums2 = new List<int> { 4, 5, 2, 7, 1, 10 }; nums3 = new Dictionary<int, int> { [2] = 4, [3] = 5, [6] = 2, [9] = 7, [1] = 1, [4] = 10 }.Values.ToList(); Run(nums1.Concat(nums2).Concat(nums3)); } static void Run(IEnumerable<int> nums) { Write($"DATA = "); nums.ToList().ForEach(n => Write($"{n} ")); Show(MaxMixAverage(nums)); } static (int max, int min, float average) MaxMixAverage(IEnumerable<int> nums) => (nums.Max(), nums.Min(), (float)nums.Average()); static void Show((int max, int min, float average) calc) { WriteLine(); WriteLine($"最大(MAX) = {calc.max}"); WriteLine($"最小(MIN) = {calc.min}"); WriteLine($"平均値(AVERAGE) = {calc.average}"); } } }
汎用性を少し残しつつ、結果だけ求めると
using System.Collections.Generic; using System.Linq; using static System.Console; namespace BasicToevelopment { class Program { static void Main() { IEnumerable<int> nums1, nums2, nums3; nums1 = new int[] { 4, 5 }; nums2 = new List<int> { 2, 7 }; nums3 = new Dictionary<int, int> { [1] = 1, [4] = 10 }.Values.ToList(); var num = nums1.Concat(nums2).Concat(nums3); Write($"DATA = "); num.ToList().ForEach(n => Write($"{n} ")); WriteLine($"\n最大(MAX) = {num.Max()}\n最小(MIN) = {num.Min()}\n平均値(AVERAGE) = {num.Average()}"); } } }
若干のフォーマットを残しつつ、結果だけ表示するコード
using System.Collections.Generic; using System.Linq; using static System.Console; namespace BasicToevelopment { class Program { static void Main() { var num = new int[] { 4, 5, 2, 7, 1, 10 }; Write($"DATA = "); num.ToList().ForEach(n => Write($"{n} ")); WriteLine($"\n最大(MAX) = {num.Max()}\n最小(MIN) = {num.Min()}\n平均値(AVERAGE) = {num.Average()}"); } } }
機能確認だけのコード
ただ単に確認のため結果だけ欲しい場合、これだけでもいいですね
var num = new int[] { 4, 5, 2, 7, 1, 10 }; WriteLine($"{num.Max()}:{num.Min()}:{num.Average()}");
いかがでしたか?それぞれの変更で、メリットを感じされましたか?
可読性(読みやすさ)を犠牲にすると本末転倒ですが、
ディスカッション
コメント一覧
まだ、コメントがありません