3

複数の列の dataTable から重複を削除するのに最適な方法はどれですか?以下のコードは単一の列のみを対象としています。

public DataTable RemoveDuplicateRows(DataTable dTable, string colName)
{
   Hashtable hTable = new Hashtable();
   ArrayList duplicateList = new ArrayList();

   //Add list of all the unique item value to hashtable, which stores combination of key, value pair.
   //And add duplicate item value in arraylist.
   foreach (DataRow drow in dTable.Rows)
   {
      if (hTable.Contains(drow[colName]))
         duplicateList.Add(drow);
      else
         hTable.Add(drow[colName], string.Empty); 
   }

   //Removing a list of duplicate items from datatable.
   foreach (DataRow dRow in duplicateList)
      dTable.Rows.Remove(dRow);

   //Datatable which contains unique records will be return as output.
      return dTable;
}

string[] colName を使ってみました。エラーをスローしますdTable.Rows.Remove(dRow);

提案してください。

4

3 に答える 3

3

最も簡単で読みやすいのは、以下を使用することLinq-to-DataTableです。

var groups = from r in dTable.AsEnumerable()
             group r by new
             {
                 Col1 = r.Field<String>("Column1"),
                 Col2 = r.Field<String>("Column2"),
             };

// if you only want the first row of each group:
DataTable distinctTable = groups.Select(g => g.First()).CopyToDataTable();

注:フィールドと。から初期化される2つのプロパティ(と)を持つ匿名タイプでEnumerable.GroupByグループ化します。DataRowsCol1Col2DataRowColumn1Column2

したがって、のグループを取得しますIEnumerable<DataRow>Enumerable.First()各グループの最初のグループを返しますDataRow(たとえば、日付フィールドで並べ替えることにより、さまざまなメソッドを使用して保持する行を選択することもできます)。

次にCopyToDataTable、(現在の)個別のDataRowsから新しいDataTableを作成します。


.NET 2を使用している場合、可能な実装は次のとおりです。

IEqualityComparer<Object[]>辞書 のカスタムの実装:

class ObjectArrayComparer : IEqualityComparer<Object[]>
{
    public bool Equals(Object[] x, Object[] y)
    {
        if (x == null && y == null) return true;
        if (x == null || y == null) return false;
        if (x.Length  !=  y.Length) return false;       

        for (int i = 0; i < x.Length; i++)
        {
            if (x[i] == null && y[i] == null) continue;
            if (x[i] == null || y[i] == null) return false;
            if (!x[i].Equals(y[i])) return false;
        }
        return true;
    }

    public int GetHashCode(Object[] obj)
    {
        int hash = 0;
        if (obj != null)
        {
            hash = (hash * 17) + obj.Length;
            foreach (Object o in obj)
            {
                hash *= 17;
                if (o != null) hash = hash + o.GetHashCode();
            }
        }
        return hash;
    }
}

あなたのRemoveDuplicateRows方法:

public DataTable RemoveDuplicateRows(DataTable dTable, String[] colNames)
{
    var hTable = new Dictionary<object[], DataRow>(new ObjectArrayComparer());

    foreach (DataRow drow in dTable.Rows)
    {
        Object[] objects = new Object[colNames.Length];
        for (int c = 0; c < colNames.Length; c++)
            objects[c] = drow[colNames[c]];
        if (!hTable.ContainsKey(objects))
            hTable.Add(objects, drow);
    }

    // create a clone with the same columns and import all distinct rows
    DataTable clone = dTable.Clone();
    foreach (var kv in hTable)
        clone.ImportRow(kv.Value);

    return clone;
}

テスト:

var table = new DataTable();
table.Columns.Add("Colum1", typeof(string));
table.Columns.Add("Colum2", typeof(int));
table.Columns.Add("Colum3", typeof(string));

Random r = new Random();
for (int i = 0; i < 100; i++)
{
    table.Rows.Add("Colum1_" + r.Next(1, 10), r.Next(1, 10), "Colum3_" + r.Next(1, 10));
}
int rowCount = table.Rows.Count; // 100
var unique = RemoveDuplicateRows(table, new[] { "Colum1", "Colum2" });
int uniqueRowCount = unique.Rows.Count; // around 55-65
于 2012-10-17T12:29:54.443 に答える
0

以下は、私のいくつかの修正を加えたコードです。
主なアイデアは、HashTable(私のコードでは Dictionary<> )に1つの列だけの値ではなく、指定された列の値を追加し、これらのいくつかの値を原子的な方法で(単一のもののように)脅かすことです。

            // your code with minor amends
    public DataTable RemoveDuplicateRows(DataTable dTable, string[] colNames)
    {
        // note that strongly typed dictionary has replaced the hash table + it uses custom comparer 
        var hTable = new Dictionary<DataRowInfo, string>();
        var duplicateList = new ArrayList();

        //Add list of all the unique item value to hashtable, which stores combination of key, value pair.
        //And add duplicate item value in arraylist.
        foreach (DataRow drow in dTable.Rows)
        {
            var dataRowInfo = new DataRowInfo(drow, colNames);

            if (hTable.ContainsKey(dataRowInfo))
                duplicateList.Add(drow);
            else
                hTable.Add(dataRowInfo, string.Empty);
        }

        //Removing a list of duplicate items from datatable.
        foreach (DataRow dRow in duplicateList)
            dTable.Rows.Remove(dRow);

        //Datatable which contains unique records will be return as output.
        return dTable;
    }

    // Helper classes

    // contains values of specified columns
    internal sealed class DataRowInfo
    {
        public object[] Values { get; private set; }

        public DataRowInfo(DataRow dataRow, string[] columns)
        {
            Values = columns.Select(c => dataRow[c]).ToArray();
        }

        public override bool Equals(object obj)
        {
            if (ReferenceEquals(this, obj))
                return true;

            var other = obj as DataRowInfo;
            if (other == null)
                return false;

            return Equals(other);
        }

        private bool Equals(DataRowInfo other)
        {
            if (this.Values.Length != other.Values.Length)
                return false;
            for (int i = 0; i < this.Values.Length; i++)
            {
                if (AreObjectsEqual(this.Values[i], other.Values[i]))
                    return false;
            }

            return true;
        }

        private static bool AreObjectsEqual(object left, object right)
        {
            if (ReferenceEquals(left, right))
                return true;

            if (ReferenceEquals(left, null))
                return false;

            if (ReferenceEquals(right, null))
                return false;

            if (left.GetType() != right.GetType())
                return false;

            return left.Equals(right);
        }

        public override int GetHashCode()
        {
            unchecked
            {
                int hashCode = 0;
                foreach (var value in this.Values)
                {
                    hashCode = hashCode ^ ((value != null ? value.GetHashCode() : 0) * 397);
                }
                return hashCode;
            }
        }
    }

これが役立つことを願っています。

更新 コードを少し簡略化しました。

于 2012-10-17T12:48:06.893 に答える
0

Distinct on Datatable.Select ... Linkを使用できます

このリンクを参照してください

于 2012-10-17T12:26:49.870 に答える