2

I have viewed these questions which don't give me what I want: Comparing arrays in C# and Compare Two Arrays Of Different Lengths and Show Differences

I have an unknown number of of List objects of an unknown length, so there could be 2, 10, etc. lists.

I thought about using a set like structure but realized that while it can determine if all lists are equal, it won't tell me "list 2 has element A instead of element B, list 3 lacks element C, and list 7 has an additional element D.

Finally, the elements are objects, so I'll have to implement an Equals() function to compare 2 elements for equality. For example, the elements could be car objects that hold a string for manufacturer and an int for price.

Community
  • 1
  • 1
HukeLau_DABA
  • 2,384
  • 6
  • 33
  • 51
  • 3
    What's the question? Comparing the arrays or creating the `Equals` overload? – D Stanley Feb 04 '13 at 15:30
  • 1
    Do you care only about *membership*,or do you care about position? eg, do you also want "list 4 has all the same elements as list 1 but in a different order?" (And D Stanley is right: you don't have a question in your question. Ask a question if you want an answer.) – Eric Lippert Feb 04 '13 at 15:32
  • "list 2 has element A instead of element B, list 3 lacks element C, and list 7 has an additional element D" --> comparing to what? does the first list is the base for all the comparisons? – Roee Gavirel Feb 04 '13 at 15:34
  • 1. My question is comparing the LISTS, which I think would entail defining an Equals() method somewhere. 2. For 2 lists to be equal, they must have the same size and same elements in the same order. 3. Great question Roee; I'll have to think about that one. – HukeLau_DABA Feb 04 '13 at 15:34
  • 1
    It would help if you give a simple example. – Eric Lippert Feb 04 '13 at 15:35
  • Please give an example of lists and how you wish the output to be. we'll help you in the middle part (: – Roee Gavirel Feb 04 '13 at 15:35

1 Answers1

1

Okay, so you want to go for each list and determine the items that it has that aren't in at least one other list, and all of the items in at least one other list that it doesn't have.

To do that start out by finding all of the items in all lists; that is the "intersection" of each list.

Once you have that Except does all of the work for you. All items except a given list gives you the items that are in the intersection but not in that particular list, the items in the intersection Except the list is all of the items missing from the intersection.

public static IEnumerable<SetDifference<T>> ComputeDifferences<T>(IList<List<T>> lists)
{
    if (lists.Count == 0)
        yield break;

    var intersection = new HashSet<T>(lists.First());
    foreach (var list in lists.Skip(1))
    {
        intersection.IntersectWith(list);
    }

    var output = new List<SetDifference<T>>();
    foreach (var list in lists)
    {
        yield return new SetDifference<T>(
            list: list,
            additionalObjects: list.Except(intersection),
            missingObjects: intersection.Except(list));
    }
}

Here is the simple data holder used to provide the output.

public class SetDifference<T>
{
    public SetDifference(List<T> list, IEnumerable<T> additionalObjects,
            IEnumerable<T> missingObjects)
    {
        List = list;
        AdditionalObjects = additionalObjects;
        MissingObjects = missingObjects;
    }
    public List<T> List { get; private set; }
    public IEnumerable<T> AdditionalObjects { get; private set; }
    public IEnumerable<T> MissingObjects { get; private set; }
}

Note that because I'm using HashSet, as well as other set operations from LINQ, it will rely on the GetHashCode method of each of the items, so it must have an appropriate implementation given the Equals method for that object.

Servy
  • 202,030
  • 26
  • 332
  • 449