Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/ssis/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C#-查找重复行列表(需要优化)_C#_Linq_Optimization_Datatable_Duplicate Detection - Fatal编程技术网

C#-查找重复行列表(需要优化)

C#-查找重复行列表(需要优化),c#,linq,optimization,datatable,duplicate-detection,C#,Linq,Optimization,Datatable,Duplicate Detection,如果可能的话,我想用C#优化这段代码 如果少于1000行,就可以了。但当我们至少有10000个时,它开始需要一些时间。。。 这里有一个小基准: 5000行=>~2s 15000行=>~20秒 25000行=>~50s 事实上,我正在寻找重复的行 方法序列等于检查值可能是一个问题(在我的“基准测试”中,我有4个字段被认为是“keyField”…) 代码如下: private List<DataRow> GetDuplicateKeys(DataTable table, List&l

如果可能的话,我想用C#优化这段代码

如果少于1000行,就可以了。但当我们至少有10000个时,它开始需要一些时间。。。 这里有一个小基准:

  • 5000行=>~2s
  • 15000行=>~20秒
  • 25000行=>~50s
事实上,我正在寻找重复的行

方法序列等于检查值可能是一个问题(在我的“基准测试”中,我有4个字段被认为是“keyField”…)

代码如下:

private List<DataRow> GetDuplicateKeys(DataTable table, List<string> keyFields)
{
    Dictionary<List<object>, int> keys = new Dictionary<List<object>, int>(); // List of key values + their index in table
    List<List<object>> duplicatedKeys = new List<List<object>>(); // List of duplicated keys values 

    List<DataRow> duplicatedRows = new List<DataRow>(); // Rows that are duplicated

    foreach (DataRow row in table.Rows)
    {
        // Find keys fields values for the row
        List<object> rowKeys = new List<object>();
        keyFields.ForEach(keyField => rowKeys.Add(row[keyField]));

        // Check if those keys are already defined
        bool alreadyDefined = false;

        foreach (List<object> keyValue in keys.Keys)
        {
            if (rowKeys.SequenceEqual(keyValue))
            {
                alreadyDefined = true;
                break;
            }
        }

        if (alreadyDefined)
        {
            duplicatedRows.Add(row);

            // If first duplicate for this key, add the first occurence of this key
            if (!duplicatedKeys.Contains(rowKeys))
            {
                duplicatedKeys.Add(rowKeys);

                int i = keys[keys.Keys.First(key => key.SequenceEqual(rowKeys))];
                duplicatedRows.Add(table.Rows[i]);
            }
        }
        else
        {
            keys.Add(rowKeys, table.Rows.IndexOf(row));
        }
    }

    return duplicatedRows;
}
private List GetDuplicateKeys(数据表、列表关键字字段)
{
Dictionary keys=new Dictionary();//键值列表+表中的索引
List duplicatedKeys=new List();//重复键值列表
List duplicatedRows=new List();//重复的行
foreach(table.Rows中的DataRow行)
{
//查找行的键字段值
列表行键=新列表();
ForEach(keyField=>rowKeys.Add(row[keyField]);
//检查这些键是否已定义
bool-alreadyDefined=false;
foreach(在keys.keys中列出keyValue)
{
if(rowKeys.SequenceEqual(keyValue))
{
alreadyDefined=true;
打破
}
}
如果(已定义)
{
添加(行);
//如果此密钥首次重复,请添加此密钥的首次出现
如果(!duplicatedKeys.Contains(行键))
{
duplicatedKeys.Add(行键);
inti=keys[keys.keys.First(key=>key.SequenceEqual(rowKeys));
duplicatedRows.Add(表行[i]);
}
}
其他的
{
添加(rowKeys,table.Rows.IndexOf(row));
}
}
返回drows;
}

有什么想法吗?

试试这个。使用更多linq可以提高性能,如果可能,也可以尝试使用PLinq

问候

private List<DataRow> GetDuplicateKeys(DataTable table, List<string> keyFields)
{
    Dictionary<List<object>, int> keys = new Dictionary<List<object>, int>(); // List of key values + their index in table
    List<List<object>> duplicatedKeys = new List<List<object>>(); // List of duplicated keys values 

    List<DataRow> duplicatedRows = new List<DataRow>(); // Rows that are duplicated

    foreach (DataRow row in table.Rows)
    {
        // Find keys fields values for the row
        List<object> rowKeys = new List<object>();
        keyFields.ForEach(keyField => rowKeys.Add(row[keyField]));

        // Check if those keys are already defined
        bool alreadyDefined = false;

        foreach (List<object> keyValue in keys.Keys)
        {
            if (rowKeys.Any(keyValue))
            {
                alreadyDefined = true;
                break;
            }
        }

        if (alreadyDefined)
        {
            duplicatedRows.Add(row);

            // If first duplicate for this key, add the first occurence of this key
            if (!duplicatedKeys.Contains(rowKeys))
            {
                duplicatedKeys.Add(rowKeys);

                int i = keys[keys.Keys.First(key => key.SequenceEqual(rowKeys))];
                duplicatedRows.Add(table.Rows[i]);
            }
        }
        else
        {
            keys.Add(rowKeys, table.Rows.IndexOf(row));
        }
    }

    return duplicatedRows;
}
private List GetDuplicateKeys(数据表、列表关键字字段)
{
Dictionary keys=new Dictionary();//键值列表+表中的索引
List duplicatedKeys=new List();//重复键值列表
List duplicatedRows=new List();//重复的行
foreach(table.Rows中的DataRow行)
{
//查找行的键字段值
列表行键=新列表();
ForEach(keyField=>rowKeys.Add(row[keyField]);
//检查这些键是否已定义
bool-alreadyDefined=false;
foreach(在keys.keys中列出keyValue)
{
if(rowKeys.Any(keyValue))
{
alreadyDefined=true;
打破
}
}
如果(已定义)
{
添加(行);
//如果此密钥首次重复,请添加此密钥的首次出现
如果(!duplicatedKeys.Contains(行键))
{
duplicatedKeys.Add(行键);
inti=keys[keys.keys.First(key=>key.SequenceEqual(rowKeys));
duplicatedRows.Add(表行[i]);
}
}
其他的
{
添加(rowKeys,table.Rows.IndexOf(row));
}
}
返回drows;
}

我认为这是查找重复行的最快、最短的方法:

对于100000行,它在大约250ms内执行

主要
和测试数据:

static void Main(string[] args)
{
    var dt = new DataTable();
    dt.Columns.Add("Id");
    dt.Columns.Add("Value1");
    dt.Columns.Add("Value2");

    var rnd = new Random(DateTime.Now.Millisecond);
    for (int i = 0; i < 100000; i++)
    {
        var dr = dt.NewRow();
        dr[0] = rnd.Next(1, 1000);
        dr[1] = rnd.Next(1, 1000);
        dr[2] = rnd.Next(1, 1000);
        dt.Rows.Add(dr);
    }

    Stopwatch sw = new Stopwatch();
    sw.Start();
    var duplicates = GetDuplicateRows(dt, "Id", "Value1", "Value2");
    sw.Stop();
    Console.WriteLine(
        "Found {0} duplicates in {1} miliseconds.", 
        duplicates.Count,
        sw.ElapsedMilliseconds);        
    Console.ReadKey();
}
说明(适用于刚刚接触
LINQ
的人):


我想最棘手的部分是
GroupBy
。这里,我将a
DataRow
作为第一个参数,对于每一行,我从指定键的值中创建一个组键,我加入这些键,创建一个类似
1-1-2
的字符串。然后,第二个参数只是选择组键,并将组行放入一个新的匿名对象中。然后我检查是否有超过1行的内容,并使用
SelectMany

将组平铺回一个列表,因为您没有收到错误,而且您的代码基本上正常工作,我想这似乎是解决此问题的更好地方。我不知道。下次我会知道的。:-)感谢您的建议,我还不习惯使用Linq进行复杂的查询,但正如我在t3chb0t解决方案中看到的那样,这是值得学习的。我刚刚看到了您在编写
Linq
时的另一条评论;-)所以我添加了一些解释。
private static List<DataRow> GetDuplicateRows(DataTable table, params string[] keys)
{
    var duplicates =
        table
        .AsEnumerable()
        .GroupBy(dr => String.Join("-", keys.Select(k => dr[k])), (groupKey, groupRows) => new { Key = groupKey, Rows = groupRows })
        .Where(g => g.Rows.Count() > 1)
        .SelectMany(g => g.Rows)
        .ToList();

    return duplicates;
}