tags:

views:

105

answers:

3

I have a method as follows. It returns a list of MyTypes which appear to be ordered by myType.Id ascending by default. I'd like this list to be ordered by the ids parameter I pass into the method.

public List<MyType> GetMyTypes(List<int> ids)
{
return (from myType in db.MyTypes
        where ids.Contains(myType.Id)
        select new MyType
        {
            MyValue = myType.MyValue
        }).ToList();
}

So if ids contains

302
300
301

the List returned contains items in ascending order.

What do I need to do to return List<MyType> in the order of ids?

Thanks

edit: I've tried orderby ids.IndexOf(myType.Id) but it throws the exception Method 'Int32 IndexOf(Int32)' has no supported translation to SQL.

+7  A: 

EDIT: now that the mistake I made in understanding the requirement has been pointed out, I suggest this as a more performant method of achieving the desired result:

    public static List<MyType> GetMyTypes(List<int> ids)
    {
        int index = 0;
        Dictionary<int, int> positions = ids.ToDictionary(c => c, c => index++);
        MyType[] results = new MyType[ids.Count];

        foreach (MyType aType in (from myType in db.MyTypes
                                  where ids.Contains(myType.Id)
                                  orderby myType.Id
                                  select myType))
        {
            results[positions[aType.Id]] = aType;
        }

        return results.ToList();
    }

This won't do a search through the ids list for every element in db.MyTypes (which is a good thing: it'll be fast!).

My original (incorrect) answer:

Use an orderby clause.

public List<MyType> GetMyTypes(List<int> ids) 
{ 
return (from myType in db.MyTypes 
        where ids.Contains(myType.Id) 
        orderby myType.Id
        select new MyType 
        { 
            MyValue = myType.MyValue 
        }).ToList(); 
} 

It's not clear what type of object db.MyTypes returns but, at a guess, the code could be simplified a little by avoiding the newing up of more MyType objects.

public List<MyType> GetMyTypes(List<int> ids) 
{ 
return (from myType in db.MyTypes 
        where ids.Contains(myType.Id) 
        orderby myType.Id
        select myType).ToList(); 
} 
Daniel Renshaw
I think that is not what the OP wanted. The way I read the question, he wants the list ordered by the way the Id are ordered in `ids`.
Jens
DaveDev
+1 for the quickity :-) It's not my code though so I don't want to make too much of a change to it, so I'll go with the answer I posted below. Thanks for the input!
DaveDev
Thank Nicholas. I've edited the answer with a bug fix. It's had some (limited) testing this time too!
Daniel Renshaw
+5  A: 

Daniel is nearly right, but an easy way to use the order of the incoming list is to order by the index of the ID in that list:

public List<MyType> GetMyTypes(List<int> ids)  
{  
    return (from myType in db.MyTypes  
        where ids.Contains(myType.Id)  
        orderby ids.IndexOf(myType.Id)
        select myType).ToList();  
}  

Note I don't know if that will work with a SQL query, so this may be Linq-to-objects only. It could also be very inefficient with large lists of ids.

Simon Steele
+1 for spotting my poor reading skill!
Daniel Renshaw
Hi Simon, as you indicated it doesn't seem to work with LINQ to SQL. It throws the following exception: `Method 'Int32 IndexOf(Int32)' has no supported translation to SQL.`
DaveDev
I think there is a way to do this that avods the Linq to SQL issue and is also a bit more performant, see my edited answer
Daniel Renshaw
+3  A: 

The following worked:

public List<MyType> GetMyTypes(List<int> ids)
{
    var unordered = (from myType in db.MyTypes
                     where ids.Contains(myType.Id)
                     select new MyType
                     {
                         MyValue = myType.MyValue
                     }).ToList();

    var ordered = (from uo in unordered
                   orderby ids.IndexOf(uo.Id)
                   select uo).ToList();

    return ordered;

}
DaveDev
This avoids the Linq-to-Sql issue, but still could be very slow depending on the size of ids and the result set.
Simon Steele
You're right Simon. I'm allowing myself a bit of a fudge here though because I know the list of ids will always be ~4 elements long. If it was any more I'd be approaching this differently anyway. Thanks
DaveDev