2

I have a list of unique items like this:

List<Animals> ItemList = Cat, Dog, Bird, ...

I'm trying to sort it using a external priority list like this:

List<Animals> PriorityList = Dog, Cat, Bird, ...

I found out I can sort the items correctly in this way:

ItemList.OrderBy(i => i == Dog).ThenBy(i => i.Cat).ThenBy(i => i.Bird)...

But the scalability of this approach is terribly bad; do someone has an idea how to do this using LINQ and the PriorityList?

2 Answers2

6

You can order the items by their index in the other list:

var orderedList = ItemList.OrderBy(i => PriorityList.IndexOf(i)).ToList();

However, if an item happens to not be in the priority list at all, then that item will come first, because IndexOf will return -1 for an item that doesn't exist. If you'd rather have them come last, then you can check if the list contains the item first, and if it doesn't, return a larger number, like int.MaxValue or PriorityList.Count:

var ordered = items
    .OrderBy(i => priorities.Contains(i) ? priorities.IndexOf(i) : int.MaxValue)
    .ToList();
Rufus L
  • 36,127
  • 5
  • 30
  • 43
1

If the cost of looking up the priority is significant (remember there are O(n log n) comparisons, with two look-ups per comparison), then doing that lookup once is an option. Tuples avoid the need to create a type to hold the intermediate result.

var ordered = ItemList
               .Select(i => (item: i, priority: PriorityList.IndexOf(i))
               .OrderBy(i => i.priority)
               .Select(i => i.item)
               .ToList();

(I use ToList here to avoid running the sort many times if the result is enumerated multiple times.)

Richard
  • 106,783
  • 21
  • 203
  • 265
  • I didn't mention it but in my case the list will be never longer than 20-30 items, then in my case the readability of the first answer would be a better trade-off. Anyway, in case I need to reuse this code in the future it's nice to be aware of this, thanks. – C0FF33 S33D Mar 19 '19 at 12:37