0

I have two objects of type IList:

public class SampleSentence
{
    public int SampleSentenceId { get; set; } 
    public string Text { get; set; } 
}

IList<SampleSentence> Old = 
   [new SampleSentence() { SampleSentenceId = 1; Text = 'cat' }]

IList<SampleSentence> New = 
   [new SampleSentence() { Text = 'cat' }],
    new SampleSentence() { Text = 'dog' }]

What I need to get is:

IList<SampleSentence> whatINeed = 
   [new SampleSentence() { Text = 'dog' }]
  • Object Old is a list of SampleSentences with the SampleSentenceId and Text fields populated.
  • Object New is a list of SampleSentences with the only the Text fields populated. It will have the same or more rows than object Old

Using LINQ how can I compare the Old and New objects (linking them with the contents of Text) and create another IList that has the additional columns in the list named New?

Samantha J T Star
  • 30,952
  • 84
  • 245
  • 427
  • *"has the additional columns in the list named New"* additional columns? Did you mean to say addition *rows*? – Matt Burland Jun 03 '16 at 13:28
  • I'm not sure I understood well: You want to check which one are new? New.Except(Old).ToList(); You'll need to override Equals to test for Text equality – nkoniishvt Jun 03 '16 at 13:29
  • And to clarify, you want to compare *by comparing the `Text` properties* the objects in `Old` with the objects in `New` to create a new collection with the union of the two lists? If a `SampleSentence` exists in both `New` and `Old`, which one do you want to take for the new list? – Matt Burland Jun 03 '16 at 13:30
  • 2
    Possible duplicate of [LINQ - compare two lists](http://stackoverflow.com/questions/9524681/linq-compare-two-lists) – Mong Zhu Jun 03 '16 at 13:31
  • I added an example. Hope this helps. In my example I have the Old list with just one row and the New list with two rows. What I need to get is a list of the rows that are in New and not in Old. In this case a List that has the one SampleSentence with Text = 'dog' – Samantha J T Star Jun 03 '16 at 13:32
  • What I wrote will probably do what you want, find new items by comparing old and new lists – nkoniishvt Jun 03 '16 at 13:33
  • What classifies as a match? Would the match be case sensitive? – sr28 Jun 03 '16 at 13:33

2 Answers2

3

Create a custom IEqualityComparer:

public class SampleSentenceComparer : IEqualityComparer<SampleSentence> {

    public bool Equals(SampleSentence x, SampleSentence y) {
        if (x == y) return true;
        if (x == null || y == null) return false;

        return x.Text.Equals(y.Text);
    }

    public int GetHashCode(SampleSentence obj) {
        return obj.Text.GetHashCode();
    }
}

Usage:

List<SampleSentence> newItems = New.Except(Old, new SampleSentenceComparer()).ToList();
nkoniishvt
  • 2,442
  • 1
  • 14
  • 29
  • `Except` uses `GetHashCode`. But you should always override `Equals` **and** `GetHashCode` anyway. – Tim Schmelter Jun 03 '16 at 13:37
  • You should use a custom equality comparer for that task (based on delegates). Any class with an ID smells to have the default equality based on that ID. Rule Of Thumb: *Do not solve a local problem with a global solution* :o) – Sir Rufo Jun 04 '16 at 08:53
  • 1
    @SirRufo Thank you for the suggestion, I didn't know this overload. Edited as suggested – nkoniishvt Jun 06 '16 at 10:57
  • @nkoniishvt Just forget my comment ... too hot here ;o) – Sir Rufo Jun 06 '16 at 13:50
3

You can use simple antijoin implemented with LINQ GroupJoin method/operator:

IList<SampleSentence> whatINeed = New.GroupJoin(Old,
        newElement => newElement.Text, oldElement => oldElement.Text,
        (newElement, oldElements) => new { newElement, oldElements })
    .Where(match => !match.oldElements.Any())
    .Select(match => match.newElement)
    .ToList();

The same with query syntax (preferable when using joins due to transparent identifiers - note the lack of match anonymous type):

IList<SampleSentence> whatINeed =
    (from newElement in New
     join oldElement in Old on newElement.Text equals oldElement.Text into oldElements
     where !oldElements.Any()
     select newElement)
    .ToList();
Ivan Stoev
  • 195,425
  • 15
  • 312
  • 343