tags:

views:

128

answers:

5

Not entirely sure of a good title for this, feel free to edit it to a good one

I have an images object, which contains a list of organs which it is related to.

I want to query a list of images and find which ones have all of the organs in a list of organs.

Here is the method signature

public static IEnumerable<Image> WithOrgans(this IEnumerable<Image> qry, IEnumerable<Organ> organs)

Not really sure how to construct the linq for this, would appreciate some ideas, I haven't done linq in a while so am quite rusty!

UPDATE

Ok, so this is some sample data

    dictionary.Add(7, new Image { id = 7, organs = new List<Organ> { organA, organB }});
    dictionary.Add(8, new Image { id = 8, organs = new List<Organ> { organA }});
    dictionary.Add(9, new Image { id = 9, organs = new List<Organ> { organC }});
A: 

Maybe like this?

var imagesWithAllOrgans = 
    from image in qry
    where image.Organs.All(organ => organs.Contains(organ))
    select image;

This assumes that organs is an enumeration of all distinct organs you wish to compare your images with.

Joseph
That would just verify that they had the same number of items, not necessarily the same items.
Eric Petroelje
@Eric Yeah you're right, I was trying to come up with something better than that.
Joseph
+1  A: 

Assuming the associated organs of an image are stored in the collection Image.Organs, the following query will do the trick. It depends on your LINQ provider if some modification are required because of unsupported functions.

public static IEnumerable<Image> WithOrgans(
    this IEnumerable<Image> qry, IEnumerable<Organ> organs)
{
    return qry.Where(image => organs.All(organ => image.Organs.Contains(organ)));
}
Daniel Brückner
30 seconds ahead :)
JoshJordan
This seems to make sense but for some reason it is returning a "WhereListIterator", when you try and inumerate it, it gets no results
qui
Perhaps there are no results in the query that match the criterion. In that case, an empty results set is correct.
Eric Lippert
A: 

Here is an idea:

Create a query for images having each organ individually, then intersect those

(rough code)

    var imagesPerOrgan = organs.Select(organ => ImagesOrgans.Where(io => io.OrganId = organ.Id));
    var result = null;
    foreach (var item in imagesPerOrgan)
    {
        if (result == null)
        {
            result = item;
        }
        else
        {
            result = result.Intersect(result);
        }

    }
Alex Black
+10  A: 

Another way of doing it using Intersect:

from i in qry 
where i.Organs.Intersect(organs).Count == organs.Count
select i

ETA:

From your comment, you mention you are getting a WhereListIterator back. I believe that the WhereListIterator implements IEnumerable, so you are getting back exactly what you should be getting.

If you are finding that the results are empty when they shouldn't be, you might want to check to make sure your Image class implements Equals() and GetHashCode() properly so that they can be effectively compared.

Eric Petroelje
That's what I was about to suggest, +1.
Meta-Knight
Nice one. +1
Daniel Brückner
Surely this only finds the images which have the same number of organs, not the same organs?
qui
@qui: why do you say that? Can you explain?
Eric Lippert
@qui: The i.Organs.Intersect should create a new IEnumerable from the images in i.Organs that only has those items that are in both i.Organs *and* the organs variable. So if those counts are equal, then that will mean that i.Organs contains **all** of the images contained in organs.
Jacob Proffitt
Hmm, I think I understand this approach now, however I am still not getting an IEnumerable back, and rather I am getting a "WhereListIterator". I have added some sample data to the question. I would appreciate some feedback, for now, I go to google..
qui
A: 

Just for fun:

IEnumerable<Image> result = qry
  .SelectMany(i => i.Organs, (i, o) => new {i, o})
  .GroupBy(x => x.o, x => x.i}
  .Where(kvp => organs.Contains(kvp.Key))
  .Select(kvp => kvp.Value)
  .Aggregate( (z, x) => z.Intersect(x) );

With a haiku comment:

//unpack image hi-archy
//group images by organ
//filter to the list
//use the groups' values
//intersect all of those
David B