Listを使ってみる

ポンコツ2人組がC#でListを使ったプログラムに挑戦してみました! 今回は入れ子になったリストのデータをグループ化して別の構造のリストを作成し、 そのデータを使って、データの比較や存在チェックなどを行い、特定の条件を満たす行データだけを抽出しています。 開発環境はVisualStudio2022です。
C#初心者が制作したものなのでいろいろとおかしい部分が多いと思います。プログラムを流用する際は適宜修正してください。

※この記事は2023/12/23時点の情報です。

Item
テストNoと行番号をプロパティに持つクラスです。

public class Item
{
    public string? testNo { get; set; } // アイテムのテスト番号
    public int row { get; set; } // アイテムの行番号
}

RowData
行番号とItemのリストをプロパティに持つクラスです。

public class RowData
{
    public int row { get; set; } // 行データの行番号
    public List<Item>? data { get; set; } // 行データに含まれるアイテムのリスト
}

Program
今回のプログラム本体です。
■ alistは、ITEMリストを持つリストです。
■ alistの各リストごとに行番号でグループ化し、そのグループごとにRowDataクラスの新しいインスタンスをclistとして作成します。
■ clistの1件目をa、2件目をbとして、下記条件を満たすデータを抽出してdlistを作成します。
・条件1:clistの1件目(a)をループして、ループ中のRowDataの全てのItemの"testNo"が2件目(b)に存在しない場合は、 clistの1件目(a)のRowDataをdlistに追加する。ただし同じデータがdlistに存在する場合は追加しない。
・条件2:clistの2件目(b)をループして、ループ中のRowDataの全てのItemの"testNo"が1件目(a)に存在しない場合は、 clistの2件目(b)のRowDataをdlistに追加する。ただし同じデータがdlistに存在する場合は追加しない。
・条件3:clistの1件目(a)をループして、ループ中のRowDataの各Itemの"testNo"のいずれかが2件目(b)に存在する場合は、 clistの1件目(a)のRowDataをdlistに追加する。追加する位置は、testNoが一致したデータのrowが大きければdlistの先頭に追加し、 そうでなければdlistの末尾に追加する。ただし同じRowDataのいずれかのデータがdlistに存在する場合は追加しない。
・条件4:clistの2件目(b)をループして、ループ中のRowDataのいずれかのItemの"testNo"が1件目(a)に存在する場合、 clistの2件目(b)のRowDataはclistに追加しない。

using System;
using System.Collections.Generic;
using System.Linq;

class Program
{
    static void Main(string[] args)
    {
        List<List<Item>> alist = new List<List<Item>>
        {
            // alistのデータを追加
            new List<Item>
            {
                new Item { testNo = "001", row = 1 },
                new Item { testNo = "002", row = 1 },
                new Item { testNo = "003", row = 1 },
                new Item { testNo = "004", row = 2 },
                new Item { testNo = "xxx", row = 2 },
                new Item { testNo = "006", row = 2 },
                new Item { testNo = "007", row = 3 },
                new Item { testNo = "008", row = 3 },
                new Item { testNo = "009", row = 3 }
            },
            new List<Item>
            {
                new Item { testNo = "004", row = 1 },
                new Item { testNo = "005", row = 1 },
                new Item { testNo = "006", row = 1 },
                new Item { testNo = "xxx", row = 2 },
                new Item { testNo = "008", row = 2 },
                new Item { testNo = "009", row = 2 },
                new Item { testNo = "010", row = 3 },
                new Item { testNo = "011", row = 3 },
                new Item { testNo = "012", row = 3 }
            },
        };

        // alistの各要素を新しい構造のリストに変換する
        List<List<RowData>> clist = alist.Select(innerList =>
            // innerListをitem.rowでグループ化し、新しい構造のリストを作成する
            innerList.GroupBy(item => item.row)
                    // グループごとにRowDataの新しいインスタンスを作成し、rowにはグループのキー、dataにはグループ内の要素をリスト化したものを代入する
                    .Select(group => new RowData { row = group.Key, data = group.ToList() })
                    // rowData.rowを基準にRowDataのインスタンスを並び替える
                    .OrderBy(rowData => rowData.row)
                    // 新しい構造のリストを生成する
                    .ToList()
            // 最終的に新しいリストを生成する
            ).ToList();


        var dlist = new List<RowData>(); // 結果のリスト

        var a = clist[0]; // 最初のリスト
        var b = clist[1]; // 2番目のリスト

        // aの各行データがbに存在しない場合、dlistに追加
        foreach (var rowDataA in a)
        {
            bool existsInB = CheckExistenceInB(rowDataA, b); // aのデータがbに存在するかチェック
            bool existsInDlist = DataExistsInDlist(rowDataA, dlist); // dlistにすでに存在するかチェック
            if (!existsInB && !existsInDlist)
            {
                dlist.Add(rowDataA); // dlistに追加
            }
        }

        // bの各行データがaに存在しない場合、dlistに追加
        foreach (var rowDataB in b)
        {
            bool existsInA = CheckExistenceInA(rowDataB, a); // bのデータがaに存在するかチェック
            bool existsInDlist = DataExistsInDlist(rowDataB, dlist); // dlistにすでに存在するかチェック
            if (!existsInA && !existsInDlist)
            {
                dlist.Add(rowDataB); // dlistに追加
            }
        }

        // aの各行データがbに存在し、かつdlistに存在しない場合、dlistに追加
        foreach (var rowDataA in a)
        {
            bool existsInB = CheckExistenceInB(rowDataA, b); // aのデータがbに存在するかチェック
            bool existsInDlist = DataExistsInDlist(rowDataA, dlist); // dlistにすでに存在するかチェック
            if (existsInB && !existsInDlist)
            {
                AddRowDataToList(rowDataA, dlist); // dlistに追加
            }
        }

        // bの各行データがaに存在しない場合、dlistに追加
        foreach (var rowDataB in b)
        {
            bool existsInA = CheckExistenceInA(rowDataB, a); // bのデータがaに存在するかチェック
            bool existsInDlist = DataExistsInDlist(rowDataB, dlist); // dlistにすでに存在するかチェック
            if (!existsInA && !existsInDlist)
            {
                dlist.Add(rowDataB); // dlistに追加
            }
        }

        // dlistの内容を出力
        foreach (var rowDataList in dlist)
        {
            if (rowDataList.data != null)
            {
                Console.WriteLine($"Row: {rowDataList.row}"); // 行番号を表示
                for (int i = 0; i < rowDataList.data.Count; i++)
                {
                    Item? item = rowDataList.data[i]; // dataリストがnullでないことを確認した上で、そのリストから指定された位置のアイテムを抽出
                    Console.WriteLine($"TestNo: {item.testNo}, Row: {item.row}"); // アイテムのテスト番号と行番号を表示
                }
            }
        }
    }
    // CheckExistenceInBメソッド:与えられた行データが別の行データリスト(b)に存在するかを確認
    static bool CheckExistenceInB(RowData rowData, List<RowData>? b)
    {
        // 行データまたはbがnullの場合は、存在しないと判断
        if (rowData.data == null || b == null)
        {
            return false;
        }

        // 行データの各アイテムに対し、bの各行データ内の各アイテムとのテスト番号の一致を確認
        foreach (var itemA in rowData.data)
        {
            foreach (var rowDataB in b)
            {
                if (rowDataB.data == null) continue;

                foreach (var itemB in rowDataB.data)
                {
                    if (itemA.testNo == itemB.testNo)
                    {
                        return true; // 一致が見つかった場合、存在すると判断
                    }
                }
            }
        }
        return false; // 一致が見つからなかった場合、存在しないと判断
    }

    // CheckExistenceInAメソッド:与えられた行データが別の行データリスト(a)に存在するかを確認
    static bool CheckExistenceInA(RowData rowData, List<RowData>? a)
    {
        // 行データまたはaがnullの場合は、存在しないと判断
        if (rowData.data == null || a == null)
        {
            return false;
        }

        // 行データの各アイテムに対し、aの各行データ内の各アイテムとのテスト番号の一致を確認
        foreach (var itemB in rowData.data)
        {
            foreach (var rowDataA in a)
            {
                if (rowDataA.data == null) continue;

                foreach (var itemA in rowDataA.data)
                {
                    if (itemB.testNo == itemA.testNo)
                    {
                        return true; // 一致が見つかった場合、存在すると判断
                    }
                }
            }
        }
        return false; // 一致が見つからなかった場合、存在しないと判断
    }

    // DataExistsInDlistメソッド:与えられた行データが別の行データリスト(dlist)に存在するかを確認
    static bool DataExistsInDlist(RowData rowData, List<RowData>? dlist)
    {
        // 行データまたはdlistがnullの場合は、存在しないと判断
        if (rowData.data == null || dlist == null)
        {
            return false;
        }

        // dlist内の各行データに対し、rowDataに含まれるデータが全て含まれるかを確認
        return dlist.Any(d => d.data != null && d.data.All(item => rowData.data!.Any(i => i.testNo == item.testNo)));
    }

    // AddRowDataToListメソッド:与えられた行データをリストに追加する
    static void AddRowDataToList(RowData rowData, List<RowData>? dataList)
    {
        // 行データまたはdataListがnullの場合は、何もせず終了
        if (rowData.data == null || dataList == null)
        {
            return;
        }

        // 既存の行データを探し、新しい行データを適切な位置に挿入または追加
        var existingRowData = dataList.FirstOrDefault(r => r.data != null && r.data.Any(d => d.testNo == rowData.data![0].testNo));
        if (existingRowData != null && rowData.row > existingRowData.row)
        {
            dataList.Insert(0, rowData); // 既存の行よりも新しい場合、先頭に挿入
        }
        else
        {
            dataList.Add(rowData); // 既存の行よりも古い場合、末尾に追加
        }
    }
}

以下がアプリケーションを実行した結果です。一応期待通りの結果になりました。(あまり自信がありませんが・・・)

Listを使った複雑な処理

管理人情報