KyleK
KyleK

Reputation: 190

Most efficient way to determine if there are any differences between specific properties of 2 lists of items?

In C# .NET 4.0, I am struggling to come up with the most efficient way to determine if the contents of 2 lists of items contain any differences.

I don't need to know what the differences are, just true/false whether the lists are different based on my criteria.

The 2 lists I am trying to compare contain FileInfo objects, and I want to compare only the FileInfo.Name and FileInfo.LastWriteTimeUtc properties of each item. All the FileInfo items are for files located in the same directory, so the FileInfo.Name values will be unique.

To summarize, I am looking for a single Boolean result for the following criteria:

  1. Does ListA contain any items with FileInfo.Name not in ListB?
  2. Does ListB contain any items with FileInfo.Name not in ListA?
  3. For items with the same FileInfo.Name in both lists, are the FileInfo.LastWriteTimeUtc values different?

Thank you,

Kyle

Upvotes: 1

Views: 65

Answers (2)

Tim Schmelter
Tim Schmelter

Reputation: 460058

I would use a custom IEqualityComparer<FileInfo> for this task:

public class FileNameAndLastWriteTimeUtcComparer : IEqualityComparer<FileInfo>
{
    public bool Equals(FileInfo x, FileInfo y)
    {
        if(Object.ReferenceEquals(x, y)) return true;
        if (x == null || y == null) return false;
        return x.FullName.Equals(y.FullName) && x.LastWriteTimeUtc.Equals(y.LastWriteTimeUtc);
    }

    public int GetHashCode(FileInfo fi)
    {
        unchecked // Overflow is fine, just wrap
        {
            int hash = 17;
            hash = hash * 23 + fi.FullName.GetHashCode();
            hash = hash * 23 + fi.LastWriteTimeUtc.GetHashCode();
            return hash;
        }
    }
}

Now you can use a HashSet<FileInfo> with this comparer and HashSet<T>.SetEquals:

var comparer = new FileNameAndLastWriteTimeUtcComparer();
var uniqueFiles1 = new HashSet<FileInfo>(list1, comparer);
bool anyDifferences = !uniqueFiles1.SetEquals(list2);

Note that i've used FileInfo.FullName instead of Name since names aren't unqiue at all.

Sidenote: another advantage is that you can use this comparer for many LINQ methods like GroupBy, Except, Intersect or Distinct.

Upvotes: 1

code4life
code4life

Reputation: 15794

This is not the most efficient way (probably ranks a 4 out of 5 in the quick-and-dirty category):

var comparableListA = ListA.Select(a => 
    new { Name = a.Name, LastWrite = a.LastWriteTimeUtc, Object = a});
var comparableListB = ListB.Select(b => 
    new { Name = b.Name, LastWrite = b.LastWriteTimeUtc, Object = b});

var diffList = comparableListA.Except(comparableListB);

var youHaveDiff = diffList.Any();

Explanation:
Anonymous classes are compared by property values, which is what you're looking to do, which led to my thinking of doing a LINQ projection along those lines.

P.S.
You should double check the syntax, I just rattled this off without the compiler.

Upvotes: 0

Related Questions