【问题标题】:Improve Duplicate check method改进重复检查方法
【发布时间】:2012-06-27 13:10:51
【问题描述】:

早安。

使用 C sharp .net4 和 MS Visual Studio 2010。

我为我的 Windows 窗体程序开发了一个重复检查器。 当有几百条记录时,它可以完美运行,并且在我的 Datagrid 上几乎是即时的。

我注意到的问题是,当显示 6000 条记录时,它根本就不够高效,需要几分钟。

如果有人有一些好的技巧可以让这种方法更快地改进现有设计,或者我已经看过的不同方法,我正在徘徊。

再次感谢您的帮助!

代码如下:

public void CheckForDuplicate()
{
    DataGridViewRowCollection coll = ParetoGrid.Rows;
    DataGridViewRowCollection colls = ParetoGrid.Rows;
    IList<String> listParts = new List<String>();
    int count = 0;

    foreach (DataGridViewRow item in coll)
    {
        foreach (DataGridViewRow items in colls)
        {
            count++;
            if ((items.Cells["NewPareto"].Value != null) && (items.Cells["NewPareto"].Value != DBNull.Value))
            {
                if ((items.Cells["NewPareto"].Value != DBNull.Value) && (items.Cells["NewPareto"].Value != null) && (items.Cells["NewPareto"].Value.Equals(item.Cells["NewPareto"].Value)))
                {
                    if ((items.Cells["Part"].Value != DBNull.Value) && (items.Cells["Part"].Value != null) && !(items.Cells["Part"].Value.Equals(item.Cells["Part"].Value)))
                    {
                        listParts.Add(items.Cells["Part"].Value.ToString());

                        dupi = true; //boolean toggle
                    }
                }
            }
        }
    }  
    MyErrorGrid.DataSource = listParts.Select(x => new { Part = x }).ToList();     
}

如有任何问题,请告诉我,我会尽力回答。

【问题讨论】:

  • 一个简单的优化,不会对你的代码有太大的改变,不要把所有的列都看两次,外循环循环所有列,内循环从外循环所在的地方循环到最后
  • 另外。 Cells["NewPareto"] 是一个字符串查找。如果你在循环之外得到 NUMBER(表格不会在循环中改变),然后通过数字访问呢?
  • 你最初的原因是我循环获取第一个值,然后使用它作为基础,我通过第二个循环检查所有其他值以查看是否有匹配项。
  • @StevenSmith 如果您查看了我的答案,我应该补充一点,我刚刚更改了它以获得更好的解决方案,这意味着您只需为每一行进行一次单元格查找。
  • 啊,我看看这让我花了多少时间!

标签: c# .net winforms datagridview duplicates


【解决方案1】:

如果可以,您应该尝试在基础数据而不是 UI 对象上执行此操作 - 但是我有一种预感,您是从一组 DataRows 中播种的,在这种情况下您可能无法这样做。

我认为这里问题的很大一部分是按名称重复取消引用单元格,以及您重复尊重第二组单元格的事实。所以提前做好:

var first = (from row in coll.Cast<DataGridViewRow>()
            let newpareto = row.Cells["NewPareto"].Value ?? DBNull.Value
            let part = row.Cells["Part"].Value ?? DBNull.Value
            where newpareto != DBNull.Value && part != DBNull.Value
            select new 
            { newpareto = newpareto, part = part }).ToArray();

//identical - so a copy-paste job (if not using anonymous type we could refactor)
var second = (from row in colls.Cast<DataGridViewRow>()
            let newpareto = row.Cells["NewPareto"].Value ?? DBNull.Value
            let part = row.Cells["Part"].Value ?? DBNull.Value
            where newpareto != DBNull.Value && part != DBNull.Value
            select new 
            { newpareto = newpareto, part = part }).ToArray();


//now produce our list of strings
var listParts = (from f in first
                where second.Any(v => v.newpareto.Equals(f.newpareto)
                                   && !v.part.Equals(f.part))
                select f.part.ToString()).ToList(); //if you want it as a list.

【讨论】:

  • 要匹配有问题的代码,这应该是&amp;&amp; !part1.Equals(part2)
  • 好的,我做了一些测试,我的版本 3 次,你的版本 3 次。根据 4832 条记录,我的完成需要 1 分 21 秒。您的需要 57 秒才能完成。这是个好消息,因为它在 24 秒的时间里减少了一个不错的时间,但仍然需要改进呵呵
  • 快去试试你的新解决方案吧!
  • 让 newpareto = row["NewPareto"].Value ?? DBNull.Value 无法将索引应用于 windows.systems.datagridrow 类型的 [] 表达式
  • offcourse,因为我以前从未见过 select 或 let in c sharp,所以一直在徘徊,它是第 3 代语言中的某种形式的 sql 吗?
【解决方案2】:

有一种方法可以提高效率。您需要计算每个项目的 散列。具有不同哈希值的项目不可能重复。

获得哈希后,您可以按哈希排序或使用具有高效键检索的数据结构(如Dictionary&lt;TKey,TValue&gt;)来查找所有重复项。

【讨论】:

  • 虽然我原则上同意 - 这不是一个简单的解决方案:您将如何计算单元格或 DBNulls 中具有空值的哈希值?如果您采用明显的方法并使用0,则无法在此处实现相等逻辑的短路,其中任何带有nullDBNull.Value 的单元格都会被自动忽略。您最终将强制字典对这些行执行更长时间的相等性检查,因为它们将共享相同的散列。
  • @AndrasZoltan 是的,此算法要求您对一些最终不同的项目进行检查。这是它的基本属性。改进仍然很大,因为您不再需要进行 6000*6000/2 次比较。
  • 使用散列看起来很有趣,虽然我以前从未尝试过,而且我对我将它实现到我的代码中的技能有点怀疑
  • 这还有另一个有趣的问题 - 我最初错过了一个,直到 Eren 在我的第一个解决方案中指出它 - 这里的欺骗实际上是一个字段相等而另一个字段不相等- 这不可能在单个哈希中实现。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2022-12-15
  • 1970-01-01
  • 1970-01-01
  • 2014-02-02
  • 1970-01-01
  • 2016-08-08
  • 1970-01-01
相关资源
最近更新 更多