tags:

views:

79

answers:

3

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?

+2  A: 

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.

LBushkin
I appreciate the extra detail on query comprehension but unfortunately, the query returns the linkedstudents that are not in existingstudents but I needed the existingstudents that are not in linkedstudents
Neil Trodden
@Neil: My apologies ... I'll fix my answer.
LBushkin
Thanks and marked up. A shame we can't accept multiple answers as both were pretty much on the money.
Neil Trodden
A: 
    List<student> ExistingStudents = new List<student>();
    List<student> LinkedStudents = new List<student>();

    ExistingStudents.Add(new student {id=1, name="joe"});
    ExistingStudents.Add(new student { id = 2, name = "beth" });
    ExistingStudents.Add(new student { id = 3, name = "sam" });

    LinkedStudents.Add(new student { id = 2, name = "beth" });


    var students = from stud in ExistingStudents
                    where !(LinkedStudents.Select(x => x.id).Contains(stud.id))
                    select stud;

    foreach(student s in students)
    {
        System.Diagnostics.Debug.WriteLine(string.Format("id: {0}, name: {1}", s.id, s.name));
    }

simple student class:

public class student
{
    public int id;
    public string name;
}
Robaticus
+4  A: 

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();
}
Matthew Abbott