-1

I have the following list of list of Person objects

List<List<Person>> setofPersons=new List<Lits<Person>>();

I add items to it like this.

List<Person> firstPersonList=new List<Person>();
Person p1=new Person(100,"James");
Person p2=new Person(200,"Smith");
firstPersonList.Add(p1);
firstPersonList.Add(p2);

setOfPersons.Add(firstPersonList);

List<Person> secondPersonList=new List<Person>();
Person p3=new Person(100,"James");
Person p4=new Person(200,"Smith");
Person p5=new Person(300,"Thomas");
secondPersonList.Add(p3);
secondPersonList.Add(p4);
secondPersonList.Add(p5);

setOfPersons.Add(secondPersonList);

List<Person> thirdPersonList=new List<Person>();
Person p6=new Person(100,"James");
Person p7=new Person(400,"Amy");
thirdPersonList.Add(p6);
thirdPersonList.Add(p7);

setOfPersons.Add(thirdPersonList);

Now I want to find out the common objects among the lists contained in setOfPersons. This comprison should be done by person Id eg : 100,200,300 etc;

I have tried the following.

List<Person> commonPersons = setOfPersons
    .Where(i => setOfPersons.Skip(1).All(x => x.Contains(i)))
    .ToList();

But the problem is that count in commomPersons is always 0;

Can someone help me to fix this ?

EDIT I have written the following method in Person class

              public int CompareTo(object obj)
              {
                       Person p = (Person)obj;
                       if (p.personId == personId)
                             return 1;
                       else
                             return 0;


               }

Then I changed my LINQ query to the following

              List<Person> commonPersons = setofPersons[0].Where(
                                  i => setofPersons.Skip(1).All(x => i.CompareTo(x))
                              ).ToList();

It now generates a compile time error saying " cannot convert bool to int ". I'm new to LINQ. Can someone point out where I have gone wrong ?

nidarshani fernando
  • 493
  • 4
  • 10
  • 26

4 Answers4

3

The problem is that there is no way for the computer to know if 2 instances of person class are the same. To tell the .NET Runtime how to do that, make your Person class implement IComparable, and there you can specify how to compare 2 instances of Person class (in your case you would check if the Ids are equal). See here

Correction: You need to implement IEquatable, comparable is for ordering/sorting.

Karthik
  • 990
  • 10
  • 19
  • I added the CompareTo method to my Person class. But when I changed my LINQ query to contain CompareTo method it generates a compile time error saying "cannot convert bool to int ". I'm new to LINQ. Can you pls point out where I have gone wrong ? – nidarshani fernando Apr 12 '15 at 03:36
  • 1
    IComparable is for sorting, not equality. – Charles Mager Apr 12 '15 at 09:06
1

IComparable / CompareTo is used for ordering/sorting. What you should do is override Equals and GetHashCode or implement an IEqualityComparer

A simple equality implementation could look like this, for example:

public override bool Equals(object obj)
{
    var person = (Person)obj;
    return Equals(Id, person.Id);
}

public override int GetHashCode()
{
    return Id;
}

Then your common persons could be found by:

var commonPersons = firstPersonList
    .Intersect(secondPersonList)
    .Intersect(thirdPersonList);

For the intersection of multiple enumerations (e.g. a list of lists), there are more efficient ways of doing this shown in the answers to Intersection of multiple lists with IEnumerable.Intersect()

Community
  • 1
  • 1
Charles Mager
  • 25,735
  • 2
  • 35
  • 45
0

Trying to think in set... to get what you got, you need to:

  1. Flatten all data in the set into a single collection of person, then group them by person.id
  2. Then group it by the person id
  3. Finally, filter them to only the groups having the same count as the original set.

Code as follow:

var query = setOfPersons
            .SelectMany(personList => personList.Select(person => person))
            .GroupBy(person => person.Id)
            .Where(group => group.Count() == setOfPersons.Count);

See the final sample here: https://dotnetfiddle.net/gCgNBf

Jimmy Chandra
  • 6,472
  • 4
  • 26
  • 38
0

What you need to do is flatten the list of lists into a single list. To do so, you can use SelectMany.

The code would look like this:

var commonPersons = setOfPersons.SelectMany(x => x.Where(y => y.Id == 100));
druidicwyrm
  • 480
  • 2
  • 11