1

CSV ファイルから読み込んだデータ テーブルがあります。product_idデータテーブルの 2 つの列 (と) に基づいて、どの行が重複しているかを判断する必要がありますowner_org_id。これを決定したら、その情報を使用して結果を作成できます。これは、一意ではない行のみを含むデータ テーブルと、一意の行のみを含むデータ テーブルです。

ここで他の例を見てきましたが、これまでに思いついたコードはコンパイルして実行しますが、データのすべての行が一意であると考えているようです. 実際には、テスト データには 13 行あり、一意なのは 6 行だけです。明らかに、私は何か間違ったことをしています。

編集:私が注意すべきだと思ったのは、重複のある行は、その行の重複だけでなく、すべて削除する必要があるということです。たとえば、重複が 4 つある場合、3 つではなく 4 つすべてを削除し、4 つから 1 つの一意の行を残す必要があります。

EDIT2 : または、(一意の行を選択しようとするのではなく) すべての重複行を選択できれば問題ありません。どちらの方法でも、最終結果に到達できます。

処理メソッドのコード:

MyRowComparer myrc = new MyRowComparer();
var uniquerows = dtCSV.AsEnumerable().Distinct(myrc);

以下とともに:

public class MyRowComparer : IEqualityComparer<DataRow>
{
    public bool Equals(DataRow x, DataRow y)
    {
        //return ((string.Compare(x.Field<string>("PRODUCT_ID"),   y.Field<string>("PRODUCT_ID"),   true)) ==
        //        (string.Compare(x.Field<string>("OWNER_ORG_ID"), y.Field<string>("OWNER_ORG_ID"), true)));
        return
            x.ItemArray.Except(new object[] { x[x.Table.Columns["PRODUCT_ID"].ColumnName] }) ==
            y.ItemArray.Except(new object[] { y[y.Table.Columns["PRODUCT_ID"].ColumnName] }) &&
            x.ItemArray.Except(new object[] { x[x.Table.Columns["OWNER_ORG_ID"].ColumnName] }) ==
            y.ItemArray.Except(new object[] { y[y.Table.Columns["OWNER_ORG_ID"].ColumnName] });
    }

    public int GetHashCode(DataRow obj)
    {
        int y = int.Parse(obj.Field<string>("PRODUCT_ID"));
        int z = int.Parse(obj.Field<string>("OWNER_ORG_ID"));
        int c = y ^ z;
        return c;
    }
}
4

2 に答える 2

3

LINQ-To-DataSet とEnumerable.Except/を使用できIntersectます。

var tbl1ID = tbl1.AsEnumerable()
        .Select(r => new
        {
            product_id = r.Field<String>("product_id"),
            owner_org_id = r.Field<String>("owner_org_id"),
        });
var tbl2ID = tbl2.AsEnumerable()
        .Select(r => new
        {
            product_id = r.Field<String>("product_id"),
            owner_org_id = r.Field<String>("owner_org_id"),
        });


var unique = tbl1ID.Except(tbl2ID);
var both = tbl1ID.Intersect(tbl2ID);

var tblUnique = (from uniqueRow in unique
                join row in tbl1.AsEnumerable()
                on uniqueRow equals new
                {
                    product_id = row.Field<String>("product_id"),
                    owner_org_id = row.Field<String>("owner_org_id")
                }
                select row).CopyToDataTable();
var tblBoth = (from bothRow in both
              join row in tbl1.AsEnumerable()
              on bothRow equals new
              {
                  product_id = row.Field<String>("product_id"),
                  owner_org_id = row.Field<String>("owner_org_id")
              }
              select row).CopyToDataTable();

編集:明らかに、私はあなたの要件を少し誤解しています。したがって、1 つしかなくDataTable、すべての一意の行とすべての重複する行を取得したい場合は、さらに簡単です。Enumerable.GroupBy両方のフィールドを含む匿名型で使用できます。

var groups = tbl1.AsEnumerable()
    .GroupBy(r => new
    {
        product_id = r.Field<String>("product_id"),
        owner_org_id = r.Field<String>("owner_org_id")
    });
var tblUniques = groups
    .Where(grp => grp.Count() == 1)
    .Select(grp => grp.Single())
    .CopyToDataTable();
var tblDuplicates = groups
    .Where(grp => grp.Count() > 1)
    .SelectMany(grp => grp)
    .CopyToDataTable();
于 2012-05-22T17:46:55.807 に答える
1

あなたの基準はオフです。関心がない (Except除外する) オブジェクトのセットを比較しています。

代わりに、可能な限り明確 (データ型) にして、シンプルに保ちます。

public bool Equals(DataRow x, DataRow y)
{   
    // Usually you are dealing with INT keys
    return (x["PRODUCT_ID"] as int?) == (y["PRODUCT_ID"] as int?)
      && (x["OWNER_ORG_ID"] as int?) == (y["OWNER_ORG_ID"] as int?);

    // If you really are dealing with strings, this is the equivalent:
    // return (x["PRODUCT_ID"] as string) == (y["PRODUCT_ID"] as string)
    //  && (x["OWNER_ORG_ID"] as string) == (y["OWNER_ORG_ID"] as string)
}  

nullその可能性があるかどうかを確認してください。ID が null であるため、等しい行を除外したい場合があります。

を観察しint?ます。これはタイプミスではありません。可能性のある列のデータベース値を扱う場合は、疑問符が必要ですNULL。その理由は、C#NULLでは値が型で表されるためです。この場合、演算子DBNullを使用すると ( の代わりに.asnullInvalidCastExceptionINT NOT NULL(int)

同じことが文字列にも当てはまります。(string)null 以外の DB 値が必要であると主張します。

EDIT1:

タイプを間違えた。ItemArray はハッシュテーブルではありません。行を直接使用します。

EDIT2:

例を追加string、いくつかのコメント

より簡単な方法については、データテーブル内の個別の行を選択して配列に格納する方法を確認してください

EDIT3:

キャストについての説明。

私が提案した他のリンクは、あなたのコードと同じです。私はあなたの最初の意図を忘れていました;-)私はちょうどあなたのコードを見て、最も明白なエラーに応答しました、私は見ました-申し訳ありません

これが私が問題を解決する方法です

using System.Linq;
using System.Data.Linq;

var q = dtCSV
    .AsEnumerable()
    .GroupBy(r => new { ProductId = (int)r["PRODUCT_ID"], OwnerOrgId = (int)r["OWNER_ORG_ID"] })
    .Where(g => g.Count() > 1).SelectMany(g => g);

var duplicateRows = q.ToList();

これが 100% 正しいかどうかはわかりません。手元に IDE がありません。また、キャストを適切なタイプに調整する必要があります。上記の私の追加を参照してください。

于 2012-05-22T17:36:49.230 に答える