ストップforeach!LINQで集合結合する

C#

1. はじめに

2年間C#プロジェクトに携わった中でよく使ってきたLINQまとめ に引き続きLINQ記事です。 LINQを知らないと、コレクションを扱う際に、ついforeachを使ってしまうかと思います。 そのforeach、ちょっと待ってください!!! LINQを使って簡単に集合・結合操作が行えるのでまとめていきたいと思います。

2. 集合

2-1. Union (和集合)

コレクション同士を連結します。 重複するデータがある場合は1件のみに絞られます。

var listA = new string[] { "りんご", "ばなな", "ぶどう", "みかん" };
var listB = new string[] { "さくらんぼ", "ばなな", "もも", "りんご" };

var list = listA.Union(listB);
    
foreach (var item in list)
{
    System.Console.WriteLine(item);
}

<結果> Union.PNG

2-2. Concat (和集合)

コレクション同士を連結します。 重複するデータがある場合はそのまま連結されます。(Union Allのイメージです。)

void Main()
{
    var listA = new string[] { "りんご", "ばなな", "ぶどう", "みかん" };
    var listB = new string[] { "さくらんぼ", "ばなな", "もも", "りんご" };

    var list = listA.Concat(listB);
    
    foreach (var item in list)
    {
        System.Console.WriteLine(item);
    }
}

<結果> Concat.PNG

2-3. Intersect (積集合)

2つのコレクションのどちらにも含まれている要素のみ抽出します。

var listA = new string[] { "りんご", "ばなな", "ぶどう", "みかん" };
var listB = new string[] { "さくらんぼ", "ばなな", "もも", "りんご" };

var list = listA.Intersect(listB);
    
foreach (var item in list)
{
    System.Console.WriteLine(item);
}

<結果> Intersect.PNG

2-4. Except (差集合)

左側のコレクション要素から、右側のコレクション要素を引きます。

var listA = new string[] { "りんご", "ばなな", "ぶどう", "みかん" };
var listB = new string[] { "さくらんぼ", "ばなな", "もも", "りんご" };

var list = listA.Except(listB);
    
foreach (var item in list)
{
    System.Console.WriteLine(item);
}

<結果> Except.PNG

3. 結合

3-1. Join (内部結合)

指定したキーに基づいて、コレクションを内部結合します。 以下の例では「社員.部署ID」と「部署.部署ID」をキーとして結合し、 1つのコレクションを作成しています。

// 従業員
public class Employee
{
    // 従業員ID
    public int Id { get; set;}
    // 部署ID
    public int DepartmentId { get; set;}
    // 従業員名
    public string Name { get; set;}
}

// 部署
public class Department
{
    // 部署ID
    public int Id { get; set;}
    // 部署名
    public string Name { get; set;}
}

// 従業員データ
var employeeList = new List<Employee>
{
    new Employee { Id = 100, Name = "佐藤", DepartmentId = 1 },
    new Employee { Id = 101, Name = "鈴木", DepartmentId = 2 },
    new Employee { Id = 102, Name = "高橋", DepartmentId = 3 },
    new Employee { Id = 103, Name = "田中", DepartmentId = 2 },
    new Employee { Id = 104, Name = "伊藤", DepartmentId = 1 },
    new Employee { Id = 105, Name = "渡辺", DepartmentId = 3 },
    new Employee { Id = 106, Name = "山本", DepartmentId = 1 },
};

// 部署データ
var departmentList = new List<Department>
{
    new Department { Id = 1, Name = "開発部" },
    new Department { Id = 2, Name = "研究部" },
    new Department { Id = 3, Name = "総務部" }
};

var list = employeeList.Join(departmentList, e => e.DepartmentId, d => d.Id, (e, d) => new
{
    EmployeeId = e.Id,
    EmployeeName = e.Name,
    DepartmentName = d.Name
});

foreach (var item in list)
{
    System.Console.WriteLine(item);
}

<結果> Join.PNG

3-2. GroupJoin (外部結合)

指定したキーに基づいて、コレクションを外部結合します。 以下の例では、「社員.部署ID」と「部署.部署ID」をキーとして結合しますが、 紐づくキーがない場合は部署にnullを設定するようにしています。

// 従業員
public class Employee
{
    // 従業員ID
    public int Id { get; set;}
    // 部署ID(null許容型)
    public int? DepartmentId { get; set;}
    // 従業員名
    public string Name { get; set;}
}

// 部署
public class Department
{
    // 部署ID
    public int Id { get; set;}
    // 部署名
    public string Name { get; set;}
}

void Main()
{
    // 従業員データ
    var employeeList = new List<Employee>
    {
        new Employee { Id = 100, Name = "佐藤", DepartmentId = 1 },
        new Employee { Id = 101, Name = "鈴木", DepartmentId = 2 },
        new Employee { Id = 102, Name = "高橋", DepartmentId = null },
        new Employee { Id = 103, Name = "田中", DepartmentId = null },
        new Employee { Id = 104, Name = "伊藤", DepartmentId = 1 },
        new Employee { Id = 105, Name = "渡辺", DepartmentId = 3 },
        new Employee { Id = 106, Name = "山本", DepartmentId = 1 },
    };

    // 部署データ
    var departmentList = new List<Department>
    {
        new Department { Id = 1, Name = "開発部" },
        new Department { Id = 2, Name = "研究部" },
        new Department { Id = 3, Name = "総務部" }
    };
    
    var list = employeeList.GroupJoin(departmentList, e => e.DepartmentId, d => d.Id, (e, d) => new
    {
        EmployeeId = e.Id,
        EmployeeName = e.Name,
        Departments = d.DefaultIfEmpty()
    })
    .SelectMany(d => d.Departments, (e, d) => new
    {
        EmployeeId = e.EmployeeId,
        EmployeeName = e.EmployeeName,
        DepartmentName = d != null ? d.Name : "所属なし"
    });

    foreach (var item in list)
    {
        System.Console.WriteLine(item);
    }
}

<結果> GroupJoin.PNG

4. おわりに

コレクション操作はいろんな場面で使えるので、覚えておくととても便利ですね! 他にもありましたら随時更新させて頂きます。