Reputation: 47677
It seems that i'm missing something trivial.
Anyway, here it goes:
var order = new[]{1,3,2};
var foos = new[]{new Foo{Id=1}, new Foo{Id=2}, new Foo{Id=3}};
How to sort foos by order array using Linq?
Desired result:
foos == new[]{new Foo{Id=1}, new Foo{Id=3}, new Foo{Id=2}};
Edit:
Order contains Foo ids. Sorry that i didn't mention that. Sometimes it's even harder to ask question properly than to answer it. :)
Upvotes: 2
Views: 1532
Reputation: 59705
You can do this using a nested query, but it is quite inefficient with O(n²)
.
var result = order.Select(o => foos.Single(f => f.Id == o));
If 'order' may contain ids not present in 'foos', you should use SingleOrDefault()
. If foos
might contain duplicate ids, you should use First()
or FirstOrDefault()
.
var result = order
.Select(o => foos.FirstOrDefault(f => f.Id == o))
.Select(f => f != null);
Maybe even a join will work, but I am not sure if it preserves the order.
var result = Enumerable.Join(order, foos, o => o, f => f.Id, (o, f) => f);
As Jon mentioned, the join will only work correctly if the input is well formed in the same way as required by my first suggestion.
Upvotes: 1
Reputation: 1503859
Okay, the question doesn't seem to be entirely clear to me, so I'll try to clarify what I think you're asking:
Correct?
That would be:
var orderedFoos = from orderedId in order
join foo in foos on orderedId equals foo.Id into groups
select groups.Single();
You need a join ... into
to verify that you don't have any missing or duplicate IDs in foos
. It won't, however, detect if you've got missing or duplicate IDs in order
. If you know that everything will be correct (i.e. there will be exactly one entry in foos
for every entry in order
and vice versa) then a simple join is okay:
var orderedFoos = from orderedId in order
join foo in foos on orderedId equals foo.Id
select foo;
which can be expressed in dot notation as:
var orderedFoos = order.Join(foos, order => order, foo => foo.ID, (o, f) => f);
Upvotes: 3
Reputation: 532745
I'd probably use a Dictionary<int,int>
of id/ordering pairs to make the order lookup O(1) if I had a lot of these to do. Note that you would also need to handle cases where your values are missing from the ordering -- I chose to move them to the end.
var order = new Dictionary<int,int>();
order.Add( 1, 1 );
order.Add( 2, 3 );
order.Add( 3, 2 );
var orderedFoos = foos.OrderBy( f => order.Contains(f.Id) ? order[f.Id] : int.MaxValue );
Upvotes: 1
Reputation: 13044
Is this what you are trying to do?
foos.OrderBy(f => order[f.Id-1]);
If you foreach now on the output of that, printing the ID, you get: 1,3,2
Upvotes: 4
Reputation: 27937
var order = new[] { 1, 3, 2 };
var foos = new[] { new Foo { Id = 1 }, new Foo { Id = 2 }, new Foo { Id = 3 } };
var query = from o in order
join foo in foos on o equals foo.Id
select foo;
var foos2 = query.ToArray();
Upvotes: 0
Reputation: 34421
from o in order.Select((o, i) => new { o, i })
join f in foos on o.o equals f.Id
orderby o.i
select f;
Upvotes: 3