Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I use linq to return integers in one array that do not match up with an integer property of another array?

Tags:

c#

lambda

linq

I have the following method signature:

 internal static int[] GetStudentIDsThatAreNotLinked(PrimaryKeyDataV1[]
       existingStudents, IQueryable<Student> linkedStudents)

PrimaryKeyData is a class that has ServerID and LocalID integers as properties. Student is a class that (among other properties) has an integer one called StudentID.

In English, what I want to do is return an array of integers which are in existingStudents[...].ServerID but not in linkedStudents[...].StudentID

If 'existingStudents' and 'linkedStudents' were both integer arrays, I would use a linq query as below:

return from es in existingStudents where
    !linkedStudents.Contains<int>(es) select es;

..which could then be converted to an array of ints.

What I want to do is give Contains an IEqualityOperator that will consider a PrimaryKeyData class to be equal to a Student class if PrimaryKeyData.ServerID == Student.StudentID

So I think I need a lambda expression but I'm very confused on how that would be constructed.

I think I'm going in the right direction but can anyone help me over the final hurdle?

like image 405
Neil Trodden Avatar asked Jul 01 '10 14:07

Neil Trodden


Video Answer


2 Answers

So, my understanding is that you want to get all instances of PrimaryKeyDataV1 whose ServerID property doesn't exist in any of the students.StudentID property of the linkedStudents parameter?

internal static PrimaryKeyDataV1[] GetStudentsThatAreNotLinked(PrimaryKeyDataV1[] existingStudents, IQueryable<Student> linkedStudents)
{
    var results = existingStudents.Select(s => s.ServerID)
        .Except(linkedStudents.Select(link => link.StudentID))
        .ToArray();

    return existingStudents.Where(stud => results.Contains(stud.ServerID));
}

Or if you just want an array of IDs...

internal static int[] GetStudentIDsThatAreNotLinked(PrimaryKeyDataV1[] existingStudents, IQueryable<Student> linkedStudents)
{
    return existingStudents.Select(s => s.ServerID)
        .Except(linkedStudents.Select(link => link.StudentID))
        .ToArray();
}
like image 194
Matthew Abbott Avatar answered Oct 18 '22 23:10

Matthew Abbott


If you only need to return the IDs, you can use something like:

existingStudents.Select(es => es.StudentID)
              .Except(linkedStudents.Select(ls => ls.ServerID));

You can write this in query comprehension form, but I think it's less clear:

var result = (from es in existingStudents select es.StudentID);
             .Except
             (from ls in linkedStudents select ls.ServerID)

If you need to return the result as an array, just use the .ToArray() extension:

existingStudents.Select(es => es.StudentID)
              .Except(linkedStudents.Select(ls => ls.ServerID)).ToArray();

You don't need to create your own equality comparer in the case that you only need to return the set difference in IDs.

like image 39
LBushkin Avatar answered Oct 18 '22 23:10

LBushkin