C#: 演習:配列とメソッドの組み合わせ
1. バブルソート
目標:バブルソートアルゴリズムを実装し、整数配列を昇順に並べ替え、ソート前後の結果を表示する。
要件:
- 各パスで隣接する要素を比較し、それらを入れ替えるバブルソートのロジックを作成する
- ソート前後の配列の内容を表示する
- 実際に実行されたスワップの回数を数える
▶ サンプル
CSHARP
int[] numbers = { 64, 34, 25, 12, 22, 11, 90, 5 };
Console.WriteLine("Before sorting: " + string.Join(", ", numbers));
int swapCount = 0;
for (int i = 0; i < numbers.Length - 1; i++)
{
bool swapped = false;
for (int j = 0; j < numbers.Length - 1 - i; j++)
{
if (numbers[j] > numbers[j + 1])
{
(numbers[j], numbers[j + 1]) = (numbers[j + 1], numbers[j]);
swapped = true;
swapCount++;
}
}
if (!swapped) break;
}
Console.WriteLine("After sorting: " + string.Join(", ", numbers));
Console.WriteLine($"Swap count: {swapCount}");
TEXT
📖 参照専用
Before sorting: 64, 34, 25, 12, 22, 11, 90, 5
After sorting: 5, 11, 12, 22, 25, 34, 64, 90
Swap count: 20
2. 生徒の得点統計
目標:配列を使用して生徒の得点を格納し、メソッドを用いて平均点、最高点、最低点、および平均点以上の生徒の人数を算出する。
要件:
- 平均、最大値、最小値をそれぞれ計算する方法を定義する
- 平均点以上の得点を得た生徒の人数を数える
- すべての結果をフォーマットして表示する
▶ サンプル
CSHARP
int[] scores = { 85, 92, 78, 60, 95, 88, 72, 66, 91, 83 };
double average = CalcAverage(scores);
int max = CalcMax(scores);
int min = CalcMin(scores);
int aboveAvg = CountAbove(scores, average);
Console.WriteLine($"Score list: {string.Join(", ", scores)}");
Console.WriteLine($"Average: {average:F1}");
Console.WriteLine($"Highest: {max}");
Console.WriteLine($"Lowest: {min}");
Console.WriteLine($"Above average count: {aboveAvg}");
double CalcAverage(int[] arr)
{
double sum = 0;
foreach (int s in arr) sum += s;
return sum / arr.Length;
}
int CalcMax(int[] arr)
{
int max = arr[0];
foreach (int s in arr) if (s > max) max = s;
return max;
}
int CalcMin(int[] arr)
{
int min = arr[0];
foreach (int s in arr) if (s < min) min = s;
return min;
}
int CountAbove(int[] arr, double threshold)
{
int count = 0;
foreach (int s in arr) if (s > threshold) count++;
return count;
}
TEXT
📖 参照専用
Score list: 85, 92, 78, 60, 95, 88, 72, 66, 91, 83
Average: 81.0
Highest: 95
Lowest: 60
Above average count: 5
3. やることリスト
目標:文字列配列を使用して、追加、削除、表示の操作に対応したシンプルなToDoリストを実装する。
要件:
- 配列の最大容量は10項目
- 追加時にリストが満杯かどうかを確認し、削除時にはインデックスを検証する
- 追加、削除、表示のロジックをメソッドにカプセル化する
▶ サンプル
CSHARP
📖 参照専用
string[] todos = new string[10];
int count = 0;
AddItem("Learn C# arrays");
AddItem("Complete exercises");
AddItem("Review methods and parameters");
ListAll();
RemoveItem(1);
ListAll();
void AddItem(string item)
{
if (count >= todos.Length)
{
Console.WriteLine("⚠️ To-do list is full, cannot add.");
return;
}
todos[count] = item;
count++;
Console.WriteLine($"Added: {item}");
}
void RemoveItem(int index)
{
if (index < 0 || index >= count)
{
Console.WriteLine("⚠️ Invalid index, removal failed.");
return;
}
string removed = todos[index];
for (int i = index; i < count - 1; i++)
{
todos[i] = todos[i + 1];
}
todos[count - 1] = null;
count--;
Console.WriteLine($"Removed: {removed}");
}
void ListAll()
{
Console.WriteLine("--- To-Do List ---");
if (count == 0)
{
Console.WriteLine("(empty)");
return;
}
for (int i = 0; i < count; i++)
{
Console.WriteLine($"{i}. {todos[i]}");
}
}
TEXT
📖 参照専用
Added: Learn C# arrays
Added: Complete exercises
Added: Review methods and parameters
--- To-Do List ---
0. Learn C# arrays
1. Complete exercises
2. Review methods and parameters
Removed: Complete exercises
--- To-Do List ---
0. Learn C# arrays
1. Review methods and parameters
4. 簡易テキスト解析ツール
目標:入力テキストに対して単語の出現頻度分析を行い、StringBuilder を使用して結果を連結し、分析関数をメソッドにカプセル化する。
要件:
- 総単語数と総文字数を数える
- 最も長い単語を見つけよう
- StringBuilder を使用して分析レポートを作成する
- 分析ロジックを独立したメソッドに分割する
▶ サンプル
CSHARP
string text = "CSharp is a powerful programming language and programming is fun";
int wordCount = CountWords(text);
int charCount = CountChars(text);
string longest = FindLongestWord(text);
var report = BuildReport(text, wordCount, charCount, longest);
Console.WriteLine(report);
int CountWords(string input)
{
if (string.IsNullOrWhiteSpace(input)) return 0;
string[] words = input.Split(' ', StringSplitOptions.RemoveEmptyEntries);
return words.Length;
}
int CountChars(string input)
{
return input.Length;
}
string FindLongestWord(string input)
{
if (string.IsNullOrWhiteSpace(input)) return "";
string[] words = input.Split(' ', StringSplitOptions.RemoveEmptyEntries);
string longest = words[0];
foreach (string w in words)
{
if (w.Length > longest.Length) longest = w;
}
return longest;
}
StringBuilder BuildReport(string input, int words, int chars, string longestWord)
{
var sb = new StringBuilder();
sb.AppendLine("===== Text Analysis Report =====");
sb.AppendLine($"Original: {input}");
sb.AppendLine($"Word count: {words}");
sb.AppendLine($"Character count: {chars}");
sb.AppendLine($"Longest word: {longestWord} ({longestWord.Length} chars)");
sb.Append("===== Analysis Complete =====");
return sb;
}
TEXT
📖 参照専用
===== Text Analysis Report =====
Original: CSharp is a powerful programming language and programming is fun
Word count: 10
Character count: 60
Longest word: programming (11 chars)
===== Analysis Complete =====
❓ よくある質問
Q バブルソートにおいて、
if (!swapped) breakはどのような役割を果たしますか?A 1回のパスで入れ替えが発生しなければ、配列はすでにソート済みです。早期に処理を終了させることで、不要な反復を避け、時間を節約できます。
Q ToDoリストから要素を削除した後、なぜ配列を前方へずらす必要があるのですか?
A 配列は連続した領域に格納されます。中央の要素を削除した後、その後に続く要素を前方へずらして空きを埋める必要があります。そうしないと、空白の領域ができてしまいます。
Q StringBuilderと、
+を使った文字列の連結との違いは何ですか?A StringBuilderはメモリ内の同じバッファを再利用するため、連結のたびに新しい文字列オブジェクトが作成されるのを防ぎます。連結回数が多くなるほど、パフォーマンスが向上します。
Q
StringSplitOptions.RemoveEmptyEntriesはどのような働きをしますか?A デフォルトでは、Split は空の文字列エントリを保持します。このオプションを追加すると、連続する区切り文字によって生成された空の項目が自動的に削除されます。
📖 まとめ
- バブルソートは、ネストされたループと各パスごとの交換によって昇順を実現する。早期終了の最適化により、不要な探索回数を削減する。
- 配列をメソッドの引数として渡すことで、メソッド内で配列を走査・計算できるようになり、メインのロジックを明確なままに保つことができます
- 配列ベースのToDoリストでは、要素数の管理や位置の移動を手動で行う必要があり、これが配列の固定サイズという性質を如実に示している
- StringBuilder は、繰り返し行われる文字列の連結に適しています。メソッドに分解することで、テキスト解析ロジックの保守や再利用が容易になります。
📝 練習問題
- バブルソートを修正して降順で並べ替え、各パス終了後に中間結果を出力するようにする
- 学生の得点統計に、不合格(60未満)のすべての得点のインデックスのリストを返すメソッドを追加する
- ToDoリストに「完了マーク」機能を追加する。完了した項目には、先頭に
[✓]と表示されるようにする - テキストアナライザーに単語出現頻度の集計機能を追加し、各単語の出現回数を出力するようにする