【问题标题】:OrderBy Enum but not by the value of my enumOrderBy Enum 但不是我的枚举值
【发布时间】:2020-01-12 20:28:50
【问题描述】:

我有一个包含优先级枚举变量的“任务”列表。我需要按优先级排序此列表,但我的优先级规则不是基于枚举值、枚举名称或枚举描述。我的优先级基于随时可能改变的规则。

假设此时我必须按照我的 PriorityType IZ = 3 的任务必须在列表末尾的规则对我的所有任务进行排序。所有其他任务都必须先完成,所有任务之间没有优先级。

另一个规则可能是先订购任务 HT = 1,然后我不在乎,但最后 RF = 4。

public enum PriorityType
    {
        [Description("who")]
        CL = 0,

        [Description("one")]
        HT = 1,

        [Description("exe)]
        SL = 2,

        [Description("bar")]
        IZ = 3,

        [Description("foo")]
        RF = 4
    }

没有相关性和使用枚举器名称、值或描述的可能性,并且在我的软件中优先级可能会改变。

使用 LINQ 我这样做了,但结果没有排序

void Main()
{
    var list = new Dictionary<string, QueueType>();
    list.Add("one", QueueType.CL);
    list.Add("two", QueueType.CL);
    list.Add("three", QueueType.HT);
    list.Add("four", QueueType.IZ);
    list.Add("five", QueueType.RF);
    list.Add("six", QueueType.SL);

    list.OrderBy(y => y.Value == QueueType.HT)
        .ThenBy(y => y.Value == QueueType.RF);
}

// Define other methods and classes here
public enum QueueType
{
    CL = 0,
    HT = 1,
    SL = 2,
    IZ = 3,
    RF = 4
}

这可能吗? 是的,但有简单的方法吗? 使用 LinQ?

【问题讨论】:

  • 有可能——这只是意味着您需要实现自己的IComparer&lt;T&gt; 并将其传递给OrderBy
  • 并注意 linq 操作不会改变源集合

标签: c# linq enums


【解决方案1】:

看起来您希望调用OrderBy() 中的参数来选择要移动到前面的元素。 这不是它的工作原理。 相反,这个参数选择要传递给比较器函数的值。

对于问题中的OrderBy() 调用,当您有QueueType.HT 时,您将值true 传递给比较器。如果还有其他内容,则将值 false 传递给比较器。老实说,我不确定它会如何处理这些 true/false 值,但如果有什么我希望与您想要的完全相反的顺序...... false 将与 @987654331 进行比较@value 和 true 作为 1,你最终会得到你想要的相反的顺序。由this example. 提出的

表达意图的更好方式可能如下所示:

list.OrderBy(y => y.Value == QueueType.HT? 0 : y.Value == QueueType.RF? 1 : 2).Dump();

虽然我不太喜欢嵌套三元运算符。这是将其转换为单个 lambda 表达式的最简单方法,但我可能会再次将其重写为更具可读性的内容。

关键是至少现在我们对所有对排序有意义的数字都有了值......但仍然存在问题。

这里尚不清楚 Dump() 扩展在做什么,但问题中显示的输出图像看起来与 Visual Studio 调试器的输出类似 LOT。你知道那些OrderBy()ThenBy() 调用并没有改变原来的集合,对吧?它们返回一个按该顺序在集合上循环的序列,但实际集合仍然没有改变。因此,如果您在这里查看 Visual Studio 调试器,当然您看到的内容仍然与您输入的顺序匹配。

【讨论】:

  • 抱歉 Dump() 来自 LINQPad。我总是假设每个人都知道这个工具。你是对的,我应该提到它或从我的样本中删除它。 linqpad.net
  • Gotcha.... 我用过它,但已经很久了。可能 linqpad 的 Dump() 正在为其输出查找原始字典对象......根据定义,字典是 unordered 的。如果您实际上将OrderBy() 结果放入foreach 循环中,您可能会得到至少更有意义的结果......不过,我认为您再次误解了如何使用OrderBy()。跨度>
  • 智能解决方案。为什么我自己不这么想?我也不喜欢嵌套三元运算符,但我目前没有更好的解决方案。感谢您的帮助。
【解决方案2】:

一个好的方法是将优先级逻辑封装到IComparer&lt;QueueType&gt; 实现中,这类似于策略模式。

对于您的示例,您可以使用以下内容:

public class DictionaryComparer<TKey> : IComparer<TKey>
    {
        public DictionaryComparer(IDictionary<TKey, int> priorityMap, int defaultPriority)
        {
            // TODO: add validations
            this.PriorityMap = new Dictionary<TKey, int>(priorityMap);
            this.DefaultPriority = defaultPriority;
        }

        public int DefaultPriority{get;}

        public IReadOnlyDictionary<TKey, int> PriorityMap{get;}

        public int Compare(TKey x, TKey y)
            => this.SafeAccess(x).CompareTo(this.SafeAccess(y));

        private int SafeAccess(TKey key) 
            => this.PriorityMap.TryGetValue(key, out var value)
               ? value 
               : this.DefaultPriority;
    }

并按如下方式使用:

var priorities = new Dictionary<QueueType, int>()
        {{QueueType.HT, 0}, {QueueType.RF, 1}};
var sorted = list.OrderBy(y => y.Value, new DictionaryComparer<QueueType>(priorities, int.MaxValue));

可以在this netfiddle中找到一个工作示例

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-08-20
    • 2013-09-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多