比较集合的集合

本文关键字:集合 比较 | 更新日期: 2023-09-27 18:24:09

我有一个名为Folder的类,它看起来像

public class Folder
{
  public int Id{get;set;}
  public string Titel{get;set;}
  public List<Folder> Folders{get;set;}
  public List<Document> Documents{get;set;}
}

我每10秒钟从数据库中得到一个文件夹列表。现在我需要将新的文件夹列表与内存中已有的文件夹列表进行比较。

最好的方法是什么?

我的第一个方法是:

if(currentFolders.GetHashCode() != newFolders.GetHashCode())
{
  // Work with changed data
}

此外,如果两个集合相同,我会得到不同的哈希代码。

我的第二次尝试是将类标记为[Serializable],并将两个列表序列化为Byte[]

byte[] b1, b2;
    using (var m1 = new MemoryStream())
    {
        using (var m2 = new MemoryStream())
        {
            var binaryFormatter = new BinaryFormatter();
            binaryFormatter.Serialize(m1, newFolders);
            b1 = m1.ToArray();
            binaryFormatter.Serialize(m2, currentFolders);
            b2 = m2.ToArray();
        }
    }

不幸的是,Folder-class是通过Linq2SQL自动生成的,所以我不能轻易地将其标记为Serializable

我还能做些什么来比较这两个系列?

比较集合的集合

提供:

  • Document类只有一个Name属性
  • 您的集合不包含null实例
  • 如果相等,则比较应返回true,否则返回false

您可以执行以下操作:

public bool Compare(Document expected, Document actual)
{
  return (actual.Name == expected.Name);
}
public bool Compare(Folder expected, Folder actual)
{
  return (actual.Id == expected.Id) &&
         (actual.Titel == expected.Titel) &&
         Compare(actual.Documents, expected.Documents, Compare) &&
         Compare(actual.Folders, expected.Folders, Compare);
}
public bool Compare<T>(ICollection<T> expected, ICollection<T> actual, 
                       Func<T, T, bool> comparer)
{
  return (actual.Count == expected.Count) &&
          actual.Zip(expected, (left, right) => comparer(left, right)).
          All(comparison => comparison);
}

可以通过以下方式使用:

List<Folder> previous = ...
List<Folder> current = /* Get from DB */
if (!Compare(previous, current))
{
  // Something changed
}

您还可以实现IEqualityComparer实现

我自己用解决了这个问题

internal class FolderComparer
{
    internal bool AreCollectionsEqual(IEnumerable<Folder> folderList1, IEnumerable<Folder> folderList2)
    {
        var flatFolderList1 = BuildFlatFolderList(folderList1);
        var flatFolderList2 = BuildFlatFolderList(folderList2);
        return !flatFolderList1.Except(flatFolderList2).Any();
    }

    private IEnumerable<int> BuildFlatFolderList(IEnumerable<Folder> folders)
    {
        List<int> folderIdList = new List<int>();
        DoBuildFlatFolderList(folders, folderIdList);
        return folderIdList;
    }
    private void DoBuildFlatFolderList(IEnumerable<Folder> folders, ICollection<int> resultList)
    {
        foreach (var folder in folders)
        {
            resultList.Add(folder.Id);
            DoBuildFlatFolderList(folder.Folders.ToList(), resultList);
        }    
    }
}