【问题标题】:Compare 2 lists with better performance possible?比较性能更好的 2 个列表?
【发布时间】:2018-10-31 16:04:27
【问题描述】:

我有 2 个列表。一个是文件夹中所有文件的列表,另一个是数据库中的列表。我必须比较这些列表,我想知道是否有更好的方法来做到这一点,因为我认为性能会受到影响。以下是我的一些方法:

for(int i=0; i < docListFallback.Count; i++ )
{
    if (docListFallback[i].id == metadataItem.UniqueID.ToString())
    {
        if (docListFallback[i].modifiedDate < metadataItem.Geaendert)
        {
            isDocumentMissing = true;
            downloadFile = isDocumentMissing;
        }
        docListFallback.Remove(docListFallback[i]);
        break;
    }
}

还有这个

for (int i = 0; i < docListModDate.Count; i++)
{
    if (docListModDate[i].id == metadataItem.UniqueID.ToString())
    {
        if (docListModDate[i].modifiedDate != metadataItem.Geaendert)
        {
           await _spManager.fileStorage.modifyDate(metadataItem.Geaendert, docListModDate[i].id);
        }
        docListModDate.Remove(docListModDate[i]);
        break;
    }
}

还有这个

for(int i = 0; i < cleanupDocList.Count; i++)
{
    for(int j = 0; j < existingDocuments.Count; j++)
    {
        if(cleanupDocList[i].id == existingDocuments[j].UniqueID.ToString())
        {
            addToDelList = false;
            break;
        }
        else
        {
            addToDelList = true;
        }
    }
    if(addToDelList)
    {
        toDelete.Add(cleanupDocList[i].filename);
    }
}

foreach(string fileToDelete in toDelete)
{
    await _spManager.fileStorage.DeleteFileAsync(fileToDelete);
}

【问题讨论】:

  • 拥有一个排序列表会带来很多优化选项。
  • 你需要什么作为输出,一个布尔值表示列表相等或仅匹配项的列表?
  • 您应该问自己的第一个问题是“它必须有多快?”第二个是“它有多快?”也许您根本不需要更改任何内容(尽管@Martin 的回答也使您的代码更易于阅读,因此总体而言也不错)。

标签: c# performance for-loop foreach uwp


【解决方案1】:

性能问题就在这里:

for(int i = 0; i < cleanupDocList.Count; i++)
{
    for(int j = 0; j < existingDocuments.Count; j++)
    {
      ...
    }
}

这里发生的是对于cleanupDocList 中的每个文件,您正在枚举existingDocuments 中的所有文件。这意味着如果两个列表中都有 N 个文件,则时间复杂度为 O(N^2),这不是最优的。

在这种情况下你可以观察到你唯一感兴趣的是UniqueID,所以你可以做的是首先在existingDocuments列表中构建一个HashSet&lt;string&gt;,然后检查是否该项目存在于哈希集中。这要快得多,因为HashSet&lt;&gt; 被实现为hash table,它具有恒定的平均查找时间复杂度(O(1)),这意味着我们总体上达到了O(N*1)=O(N) 时间复杂度,这很重要,尤其是在@ 987654332@ 增长。

代码如下所示:

var existingIds = new HashSet<string>(
        existingDocuments.Select(doc => doc.UniqueID.ToString()));

for(int i = 0; i < cleanupDocList.Count; i++)
{
    if (existingIds.Contains(cleanupDocList[i].id))
    { 
        toDelete.Add(cleanupDocList[i].filename);
    }
}

foreach(string fileToDelete in toDelete)
{
    await _spManager.fileStorage.DeleteFileAsync(fileToDelete);
}    

很棒的是,这种方法不仅提高了性能,而且同时大大简化了代码。让我们称之为双赢:-)!

【讨论】:

    【解决方案2】:

    我会使用 Linq 的 Except() 来执行此操作,以进行双向比较以查找 list1 中但不在 list2 中的所有项目,反之亦然。

    这是一个仅使用字符串列表的示例。这也显示了如何在两个列表中查找项目:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    
    namespace Demo
    {
        static class Program
        {
            public static void Main()
            {
                List<string> list1 = new List<string>{"A", "B", "C", "D", "E"};
                List<string> list2 = new List<string>{"D", "E", "F", "G", "H"};
    
                var inList1ButNotList2 = list1.Except(list2);
                var inList2ButNotList1 = list2.Except(list1);
                var inBothLists        = list1.Intersect(list2);
    
                Console.WriteLine("In list1 but not list2 = " + string.Join(", ", inList1ButNotList2));
                Console.WriteLine("In list2 but not list1 = " + string.Join(", ", inList2ButNotList1));
                Console.WriteLine("In both lists          = " + string.Join(", ", inBothLists));
            }
        }
    }
    

    要对您的问题使用这种方法,您需要有两个相同类型的项目集合进行比较,以及一个比较方法。在上面的代码中,我只是使用默认的字符串相等比较器,但您可以创建自己的相等比较器,如下所示:

    public class MyComparer : IEqualityComparer<string> // Instead of string, put your own type.
    {
        public bool Equals(string x, string y)
        {
            return string.Equals(x, y); // You'd implement your own comparison here.
        }
    
        public int GetHashCode(string obj)
        {
            return obj.GetHashCode();
        }
    }
    

    您可以将其传递给Except() 方法:

    static class Program
    {
        public static void Main()
        {
            List<string> list1 = new List<string>{"A", "B", "C", "D", "E"};
            List<string> list2 = new List<string>{"D", "E", "F", "G", "H"};
    
            var comparer = new MyComparer();
    
            var inList1ButNotList2 = list1.Except(list2,    comparer);
            var inList2ButNotList1 = list2.Except(list1,    comparer);
            var inBothLists        = list1.Intersect(list2, comparer);
    
            Console.WriteLine("In list1 but not list2 = " + string.Join(", ", inList1ButNotList2));
            Console.WriteLine("In list2 but not list1 = " + string.Join(", ", inList2ButNotList1));
            Console.WriteLine("In both lists          = " + string.Join(", ", inBothLists));
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-06-26
      • 1970-01-01
      • 1970-01-01
      • 2013-12-19
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多