C# と VB.NET の質問掲示板

ASP.NET、C++/CLI、Java 何でもどうぞ

C# と VB.NET の入門サイト

Re[5]: 複数の条件を満たしかつ重複をなくしてリストにする方法


(過去ログ 158 を表示中)

[トピック内 11 記事 (1 - 11 表示)]  << 0 >>

■91960 / inTopicNo.1)  複数の条件を満たしかつ重複をなくしてリストにする方法
  
□投稿者/ 河童 (61回)-(2019/08/15(Thu) 01:08:45)

分類:[C#] 

複数の条件を満たしかつ重複をなくしてリストにする方法を教えてください。

リストの「setGroup」から設定した条件で抽出できて、かつ重複のデータをなくしたいです。
setGroup:
シリーズ プロセス グループ
S1        P1        G1
S1        P2        G2
S1        P3        G3
S2        P1        G1
S2        P2        G2
S2        P3        G3
S3        P1        G4
S3        P2        G5
S3        P3        G6

条件は、シリーズとプロセスで判定します。
条件の設定は、必須ではなく空白になることもあります。
両方とも空白、両方とも入力、そして片方のみ。

条件で抽出したデータからグループのリストを作成したいです。
そのときグループ名が重複しないように作成したいです。

例えば、条件がプロセス「P1」だったとき
グループのリスト
G1
G4
としたいです。

わからないことは、
1.条件の設定
シリーズとプロセスの条件を組み合わせて設定する方法がわかりません。

2.重複データの判定方法
シリーズとプロセスの条件を満たしかつグループが重複しないようにリストを
作成する方法がわかりません。


ご教示よろしくお願いします。


       public class DataGroup
        {
            public string siries { get; set; }   
            public string process { get; set; }
            public string group { get; set; }   
        }

        public List<DataGroup> setGroup;  


        void Create_DataLst(string strWhere1, string strWhere2)
        {

            // グループリスト作成
            List<string> DataLst = new List<string>();

            for (int i = 0; i < setGroup.Count; i++)
            {
                bool kubun = false;

                // シリーズ判定
                if (strWhere1 != "")
                {
                    if (strWhere1 == setGroup[i].siries)
                    {
                        kubun = true;
                    }

                }
                // プロセス判定
                if (strWhere2 != "")
                {
                    if (strWhere2 == setGroup[i].process)
                    {
                        kubun = true;
                    }
                }

                if (kubun == true)
                {
                    // 重複ない場合、リストにセット
                    string group = setGroup[i].group;
                    DataLst.Add(group);
                }

            }

        }

引用返信 編集キー/
■91961 / inTopicNo.2)  Re[1]: 複数の条件を満たしかつ重複をなくしてリストにする方法
□投稿者/ WebSurfer (1868回)-(2019/08/15(Thu) 07:41:44)
No91960 (河童 さん) に返信

Linq は使わない条件ですか?
引用返信 編集キー/
■91962 / inTopicNo.3)  Re[1]: 複数の条件を満たしかつ重複をなくしてリストにする方法
□投稿者/ 大谷刑部 (4回)-(2019/08/15(Thu) 09:38:41)
単純化できそうなロジックをわざわざ難しく書こうとしているように見えます。

No91960 (河童 さん) に返信
> 複数の条件を満たしかつ重複をなくしてリストにする方法を教えてください。
>
> リストの「setGroup」から設定した条件で抽出できて、かつ重複のデータをなくしたいです。
> setGroup:
> シリーズ プロセス グループ
> S1 P1 G1
> S1 P2 G2
> S1 P3 G3
> S2 P1 G1
> S2 P2 G2
> S2 P3 G3
> S3 P1 G4
> S3 P2 G5
> S3 P3 G6
>
> 条件は、シリーズとプロセスで判定します。
> 条件の設定は、必須ではなく空白になることもあります。
> 両方とも空白、両方とも入力、そして片方のみ。
>
> 条件で抽出したデータからグループのリストを作成したいです。
> そのときグループ名が重複しないように作成したいです。
>
> 例えば、条件がプロセス「P1」だったとき
> グループのリスト
> G1
> G4
> としたいです。
>
> わからないことは、
> 1.条件の設定
> シリーズとプロセスの条件を組み合わせて設定する方法がわかりません。
>
> 2.重複データの判定方法
> シリーズとプロセスの条件を満たしかつグループが重複しないようにリストを
> 作成する方法がわかりません。
>
>
> ご教示よろしくお願いします。
>
>
> public class DataGroup
> {
> public string siries { get; set; }
> public string process { get; set; }
> public string group { get; set; }
> }
>
> public List<DataGroup> setGroup;

そもそもこの程度の内容クラスにする必要がありますか?
配下にメソッドもないのに。
構造体配列で十分な気がします。

重複チェック云々のロジックを簡素化したいなら、
以下のロジックでも参考にしてはいかが?↓
http://umayadia.cloudapp.net/article/Visual%20Basic/List%E3%82%84%E9%85%8D%E5%88%97%E3%81%8B%E3%82%89%E9%87%8D%E8%A4%87%E3%82%92%E6%8E%92%E9%99%A4%E3%81%99%E3%82%8B
引用返信 編集キー/
■91963 / inTopicNo.4)  Re[2]: 複数の条件を満たしかつ重複をなくしてリストにする方法
□投稿者/ WebSurfer (1869回)-(2019/08/15(Thu) 10:00:52)
No91962 (大谷刑部 さん) に返信

> そもそもこの程度の内容クラスにする必要がありますか?
> 配下にメソッドもないのに。
> 構造体配列で十分な気がします。

質問者さんが書いたようなクラスを定義して、それを
ベースに List<T> 型オブジェクトを作り上げ、Linq
で操作するということは今時ごく普通に行われていて、
何の違和感もありませんけど?

なにか問題がありますか?
引用返信 編集キー/
■91964 / inTopicNo.5)  Re[2]: 複数の条件を満たしかつ重複をなくしてリストにする方法
□投稿者/ 河童 (62回)-(2019/08/15(Thu) 10:27:20)
No91961 (WebSurfer さん) に返信

WebSurferさん、お返事ありがとうございます。

Linq での方法をお教えください。
WHERE条件を動的に組み立てるには、どうのように設定するのでしょうか?
例えば、
strWhere1はシリーズの条件になっていますが、
strWhere1が空白のときは、シリーズが空白のものを抽出するのではなく
シリーズ条件は無視したいです。

WHERE条件がある場合とない場合とグループの値でグループ化したいです。



Linq を使わない方法は下記のように修正しました。


public class DataGroup
{
    public string siries { get; set; }   
    public string process { get; set; }
    public string group { get; set; }   
}

public List<DataGroup> setGroup;  // グループリスト

void Create_DataLst(string strWhere1, string strWhere2)
{

    // グループリスト(重複なし)作成
    List<string> DataLst = new List<string>();

    string group = "";
    for (int i = 0; i < setGroup.Count; i++)
    {
    
        // 条件がない場合
        if (strWhere1 == "" && strWhere2 == "")
        {
            group = setGroup[i].group;   
        }
        // 条件が両方ある場合
        else if (strWhere1 != "" && strWhere2 != "")
        {
            if (strWhere1 == setGroup[i].siries && strWhere2 == setGroup[i].process)
            {
                group = setGroup[i].group;
            }
        }
        // シリーズ条件ありプロセス条件がない場合
        else if (strWhere1 != "" && strWhere2 == "")
        {
            if (strWhere1 == setGroup[i].siries)
            {
                group = setGroup[i].group;
            }
        }
        // シリーズ条件なくプロセス条件がある場合
        else if (strWhere1 == "" && strWhere2 != "")
        {
            if (strWhere2 == setGroup[i].process)
            {
                group = setGroup[i].group;
            }
        }
        // リストに追加
        if (group != "")
        {
            // リスト重複チェック
            if (DataLst.Contains(group))
            {
                // 重複あり
            }
            else
            {
                // 重複なし
                DataLst.Add(group);
            }
        }
    }
}

private void button1_Click(object sender, EventArgs e)
{            
    setGroup = new List<DataGroup>()
    {
        new DataGroup() { siries = "S1", process = "P1", group = "G1"},
        new DataGroup() { siries = "S1", process = "P2", group = "G2"},
        new DataGroup() { siries = "S1", process = "P3", group = "G3"},
        new DataGroup() { siries = "S2", process = "P1", group = "G1"},
        new DataGroup() { siries = "S2", process = "P2", group = "G2"},
        new DataGroup() { siries = "S2", process = "P3", group = "G3"},
        new DataGroup() { siries = "S3", process = "P1", group = "G1"},
        new DataGroup() { siries = "S3", process = "P2", group = "G2"},
        new DataGroup() { siries = "S3", process = "P3", group = "G3"}, 
    };
    
    // グループのみデータリストの作成(重複なし)        
    Create_DataLst(textBox1.Text, textBox2.Text);
}

引用返信 編集キー/
■91965 / inTopicNo.6)  Re[3]: 複数の条件を満たしかつ重複をなくしてリストにする方法
□投稿者/ 魔界の仮面弁士 (2303回)-(2019/08/15(Thu) 11:00:44)
No91960 (河童 さん) に返信
> public string siries { get; set; }

Siri の集団…で無いのだとしたら、
siries ではなく
Series かな。


No91964 (河童 さん) に返信
> Linq での方法をお教えください。

var q = this.setGroup.AsEnumerable();
if (textBox1.TextLength > 0) {
  var s = textBox1.Text;
  q = q.Where(d => d.siries == s);
}
if (textBox2.TextLength > 0) {
  var s = textBox2.Text;
  q = q.Where(d => d.process == s);
}
List<string> groups = q.Select(d => d.group).Distinct().ToList();
引用返信 編集キー/
■91966 / inTopicNo.7)  Re[3]: 複数の条件を満たしかつ重複をなくしてリストにする方法
□投稿者/ 魔界の仮面弁士 (2304回)-(2019/08/15(Thu) 11:09:30)
No91964 (河童 さん) に返信
> Linq を使わない方法は下記のように修正しました。

Linq 無しで重複を省いてみるのなら、
List<string> ではなく HashSet<string> を使うとか。


HashSet<string> groups = new HashSet<string>();
foreach (DataGroup dg in setGroup)
{
  if (strWhere1 != "" && dg.siries != strWhere1) { continue; }
  if (strWhere2 != "" && dg.process != strWhere2) { continue; }
  groups.Add(dg.group);
}
// List<string> DataLst = groups.OrderBy(x => x).ToList();
引用返信 編集キー/
■91969 / inTopicNo.8)  Re[3]: 複数の条件を満たしかつ重複をなくしてリストにする方法
□投稿者/ WebSurfer (1870回)-(2019/08/15(Thu) 11:45:53)
No91964 (河童 さん) に返信

> Linq での方法をお教えください。

サンプルコードを下に書いておきますので見てください。

> WHERE条件を動的に組み立てるには、どうのように設定するのでしょうか?

サンプルコードの Where メソッドの引数を見てください。

重複排除に関し一点注意。IEnumerable<T> で T が匿名型の場合は Distinct() メソッドで期待通り重複のない結果が得られますが、T にカスタムデータ型を使った場合は以下の 1 または 2 を実装する必要があります。

匿名型と Distinct メソッド
http://surferonwww.info/BlogEngine/post/2015/12/08/anonymous-type-and-distinct-method.aspx

以下のサンプルコードでは 1 の方法を使っています。

また、サンプルコードでは「グループ」の重複のみチェックしてますが、「シリーズ」「プロセス」も条件に加えたい場合は質問者さんの方で適宜変更してください。


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ConsoleAppDistinct
{
    public class DataGroup : IEquatable<DataGroup>
    {
        public string siries { get; set; }
        public string process { get; set; }
        public string group { get; set; }

        public bool Equals(DataGroup other)
        {
            if (Object.ReferenceEquals(other, null)) return false;

            if (Object.ReferenceEquals(this, other)) return true;

            return group.Equals(other.group);
        }

        // If Equals() returns true for a pair of objects  
        // then GetHashCode() must return the same value for these objects. 
        public override int GetHashCode()
        {
            return group.GetHashCode();
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            List<DataGroup> setGroup = new List<DataGroup>
            {
                new DataGroup { siries = "S1", process = "P1", group = "G1" },
                new DataGroup { siries = "S1", process = "P2", group = "G2" },
                new DataGroup { siries = "S1", process = "P3", group = "G3" },
                new DataGroup { siries = "S2", process = "P1", group = "G1" },
                new DataGroup { siries = "S2", process = "P2", group = "G2" },
                new DataGroup { siries = "S2", process = "P3", group = "G3" },
                new DataGroup { siries = "S3", process = "P1", group = "G4" },
                new DataGroup { siries = "S3", process = "P2", group = "G5" },
                new DataGroup { siries = "S3", process = "P3", group = "G6" }
            };

            string s = string.Empty;
            string p = "P1";

            IEnumerable<DataGroup> newlist = setGroup.
                                             Where(g => (string.IsNullOrEmpty(s) ? true : g.siries == s) && 
                                                        (string.IsNullOrEmpty(p) ? true : g.process == p));

            foreach (DataGroup g in newlist)
            {
                Console.WriteLine($"siries: {g.siries}, process: {g.process}, group: {g.group}");
            }

            // 結果は:
            // siries: S1, process: P1, group: G1
            // siries: S2, process: P1, group: G1
            // siries: S3, process: P1, group: G4

            Console.WriteLine("-------------------------");

            foreach (DataGroup g in newlist.Distinct())
            {
                Console.WriteLine($"siries: {g.siries}, process: {g.process}, group: {g.group}");
            }

            // 結果は:
            // siries: S1, process: P1, group: G1
            // siries: S3, process: P1, group: G4
        }
    }
}

引用返信 編集キー/
■91987 / inTopicNo.9)  Re[3]: 複数の条件を満たしかつ重複をなくしてリストにする方法
□投稿者/ 河童 (63回)-(2019/08/16(Fri) 09:06:29)
■91965 (魔界の仮面弁士 さん) に返信
LINQを使用する場合としない場合のコード、ありがとうございます。

いろんなやり方がありますね。
今回は自分にとってLINQを使用するものが分かりやすかったので
コードを修正して目的の結果を取得することができました。


■91969 (WebSurfer さん) に返信
サンプルコードを作成して頂きまして、ありがとうございます。
参考にさせていただきます。




解決済み
引用返信 編集キー/
■91994 / inTopicNo.10)  Re[4]: 複数の条件を満たしかつ重複をなくしてリストにする方法
□投稿者/ WebSurfer (1875回)-(2019/08/16(Fri) 10:47:42)
No91987 (河童 さん) に返信

> ■91969 (WebSurfer さん) に返信
> サンプルコードを作成して頂きまして、ありがとうございます。
> 参考にさせていただきます。

質問者さんの役には立たなかったようで残念です。

自分的には LINQ で Where と Distinct を使う
エッセンス的なものが詰まっていると自画自賛 (笑)
していたのですが。
引用返信 編集キー/
■91995 / inTopicNo.11)  Re[5]: 複数の条件を満たしかつ重複をなくしてリストにする方法
□投稿者/ WebSurfer (1876回)-(2019/08/16(Fri) 10:49:29)
解決ずみマークつけ忘れました。
解決済み
引用返信 編集キー/


トピック内ページ移動 / << 0 >>

このトピックに書きこむ

過去ログには書き込み不可

管理者用

- Child Tree -