プログラミングにおいて、別々の配列やリストとして管理されているデータを、一つのまとまったリストとして扱いたい場面は多々あります。
C#のLINQに含まれるConcatメソッドを使用すると、既存のコレクションの後ろに別のコレクションをそのまま連結することができます。今回は、ECサイトの受注システムにおける「午前の注文」と「午後の注文」をマージし、1日分の全注文リストを作成するシナリオを例に解説します。
Concatメソッドの概要
Concatメソッドは、2つのシーケンス(配列、Listなど)を連結し、新しいシーケンスを返します。
その動作は非常にシンプルで、「呼び出し元のコレクション」の後ろに「引数で指定したコレクション」の要素をそのまま追加します。
Unionメソッドとの違い
よく似た機能にUnionメソッドがありますが、両者には明確な違いがあります。
- Union: 重複する要素を削除します(集合和)。
- Concat: 重複する要素もそのまま残します(単純連結)。
データの順序を維持したい場合や、重複を含めて全てのデータを処理したい場合はConcatを使用します。
実践的なコード例:日次注文データの統合
以下のコードは、時間帯別に分かれている注文リストを連結し、報告用の一覧データを作成する例です。
using System;
using System.Collections.Generic;
using System.Linq;
namespace OrderProcessingSystem
{
// 注文データ
public record Order(int Id, string ItemName, int Quantity);
class Program
{
static void Main()
{
// シナリオ:
// システムの都合上、注文データが「午前分」と「午後分」に分かれて保存されている。
// これらを単純に結合して、本日1日分の全注文リストを作成したい。
// ※同じ商品が複数回注文されることもあるため、重複排除は行わない。
// 午前中の注文リスト
var morningOrders = new[]
{
new Order(101, "オフィスチェア", 1),
new Order(102, "USB-Cケーブル", 3),
new Order(103, "モニターアーム", 1)
};
// 午後の注文リスト
var afternoonOrders = new[]
{
new Order(104, "ワイヤレスマウス", 5),
new Order(105, "USB-Cケーブル", 2), // 午前と同じ商品が含まれている
new Order(106, "ノートPCスタンド", 1)
};
// Concatを使用してリストを連結
// morningOrdersの末尾にafternoonOrdersが続きます。
IEnumerable<Order> allOrders = morningOrders.Concat(afternoonOrders);
// 結果の出力
Console.WriteLine("--- 本日の全注文リスト ---");
foreach (var order in allOrders)
{
Console.WriteLine($"ID: {order.Id} | {order.ItemName} (数量: {order.Quantity})");
}
// (参考) 件数の確認
Console.WriteLine($"\n合計件数: {allOrders.Count()}件");
}
}
}
実行結果
--- 本日の全注文リスト ---
ID: 101 | オフィスチェア (数量: 1)
ID: 102 | USB-Cケーブル (数量: 3)
ID: 103 | モニターアーム (数量: 1)
ID: 104 | ワイヤレスマウス (数量: 5)
ID: 105 | USB-Cケーブル (数量: 2)
ID: 106 | ノートPCスタンド (数量: 1)
合計件数: 6件
技術的なポイントと注意点
1. 遅延実行(Deferred Execution)
Concatメソッドは遅延実行されます。メソッドを呼び出した時点ではメモリコピーなどの重い処理は発生せず、foreachなどで結果を列挙するタイミングで初めて順次アクセスが行われます。そのため、非常に大きなログファイル同士を論理的に結合して一行ずつ読み込む、といった用途でもメモリ効率よく動作します。
2. 単一要素を追加したい場合
コレクション同士ではなく、「リストの末尾に1つだけ要素を追加したい」という場合は、.NET Framework 4.7.1 / .NET Core 1.0以降で追加されたAppendメソッドが便利です。逆に先頭に追加したい場合はPrependを使用します。
// リストの末尾に単一の注文を追加
var newSequence = allOrders.Append(new Order(107, "追加注文", 1));
3. nullの扱い
Concatの引数(連結する相手のコレクション)がnullの場合、ArgumentNullExceptionが発生します。連結相手が空である可能性がある場合は、事前にチェックするか、空のコレクション(Enumerable.Empty<T>())を使用するように配慮する必要があります。
まとめ
Concatメソッドは、複数のデータソースを順番につなぎ合わせるための最も基本的な手段です。「データの加工や重複削除はせず、ありのまま全てのデータを順に処理したい」という要件に対しては、UnionではなくConcatを選択してください。シンプルかつ高速に動作するため、ログの統合やバッチ処理でのデータ集約に最適です。
