Linq OrderBy against specific values

后端 未结 8 1729
悲&欢浪女
悲&欢浪女 2020-12-04 17:41

Is there a way in Linq to do an OrderBy against a set of values (strings in this case) without knowing the order of the values?

Consider this data:

A         


        
8条回答
  •  粉色の甜心
    2020-12-04 18:34

    Combined all answers (and more) into a generic LINQ extension supporting caching which handles any data type, can be case-insensitive and allows to be chained with pre- and post-ordering:

    public static class SortBySample
    {
        public static BySampleSorter Create(IEnumerable fixedOrder, IEqualityComparer comparer = null)
        {
            return new BySampleSorter(fixedOrder, comparer);
        }
    
        public static BySampleSorter Create(IEqualityComparer comparer, params TKey[] fixedOrder)
        {
            return new BySampleSorter(fixedOrder, comparer);
        }
    
        public static IOrderedEnumerable OrderBySample(this IEnumerable source, Func keySelector, BySampleSorter sample)
        {
            return sample.OrderBySample(source, keySelector);
        }
    
        public static IOrderedEnumerable ThenBySample(this IOrderedEnumerable source, Func keySelector, BySampleSorter sample)
        {
            return sample.ThenBySample(source, keySelector);
        }
    }
    
    public class BySampleSorter
    {
        private readonly Dictionary dict;
    
        public BySampleSorter(IEnumerable fixedOrder, IEqualityComparer comparer = null)
        {
            this.dict = fixedOrder
                .Select((key, index) => new KeyValuePair(key, index))
                .ToDictionary(kv => kv.Key, kv => kv.Value, comparer ?? EqualityComparer.Default);
        }
    
        public BySampleSorter(IEqualityComparer comparer, params TKey[] fixedOrder)
            : this(fixedOrder, comparer)
        {
        }
    
        public IOrderedEnumerable OrderBySample(IEnumerable source, Func keySelector)
        {
            return source.OrderBy(item => this.GetOrderKey(keySelector(item)));
        }
    
        public IOrderedEnumerable ThenBySample(IOrderedEnumerable source, Func keySelector)
        {
            return source.CreateOrderedEnumerable(item => this.GetOrderKey(keySelector(item)), Comparer.Default, false);
        }
    
        private int GetOrderKey(TKey key)
        {
            int index;
            return dict.TryGetValue(key, out index) ? index : int.MaxValue;
        }
    }
    

    Sample usage using LINQPad-Dump():

    var sample = SortBySample.Create(StringComparer.OrdinalIgnoreCase, "one", "two", "three", "four");
    var unsorted = new[] {"seven", "six", "five", "four", "THREE", "tWo", "One", "zero"};
    unsorted
        .OrderBySample(x => x, sample)
        .ThenBy(x => x)
        .Dump("sorted by sample then by content");
    unsorted
        .OrderBy(x => x.Length)
        .ThenBySample(x => x, sample)
        .Dump("sorted by length then by sample");
    

提交回复
热议问题