【问题标题】:C# Check List is in correct order by comparing property to enum通过将属性与枚举进行比较,C# 检查列表的顺序正确
【发布时间】:2016-06-08 09:02:15
【问题描述】:

我有一个正在返回的对象列表,我需要检查它们是否由其中一个属性(如枚举中定义)以正确的顺序返回。

举一个更好的例子。假设我有一个 List(),其中包含以下内容

{ Name: "name1", Action: SomeAction.Read, Value: someValue },
{ Name: "name2", Action: SomeAction.Create, Value: someValue },
{ Name: "name3", Action: SomeAction.Update, Value: someValue },
{ Name: "name4", Action: SomeAction.Delete, Value: someValue },
{ Name: "name5", Action: SomeAction.Archive, Value: someValue }

并且枚举包含以下内容:

public enum SomeAction
{
    Read,

    Create,

    Update,

    Delete,

    Download,

    Archive,

    Restore
}

有没有一种方法可以与枚举进行比较,以检查列表是否按 Action 属性正确排序?

需要注意的一点是,列表可能不包含具有枚举中定义的所有操作的属性的对象,因此列表可能只有读/写/删除属性等。

【问题讨论】:

  • 什么顺序是正确的?枚举不是有序集合。想要的结果真的是bool吗?
  • 你知道SomeAction.Write 不存在,是错字吗?
  • 对不起,我应该澄清一下。所需的顺序是它在枚举中的显示方式
  • @TimSchmelter 可能是枚举值的 int 值

标签: c# list enums compare


【解决方案1】:

枚举可以有一个分配给它们的整数值(有些人可能称之为“序数”)。你可以通过强制转换得到这个整数值。

int valueOfEnum = (int)SomeEnum.SomeEnumValue;

在您的情况下,您没有分配整数值,这很好。如果您不分配它们,那么 C# 会自动为您分配它们。它们从0 开始,然后从那里递增。

这里是the MSDN documentation on using these enum "values"

您可以按照您希望它们出现的顺序将这些项目放入您的enum SomeAction 定义中,并让C# 自动分配这些值。这可能就是您需要做的所有事情。

您还可以为它们中的每一个分配值,以指定您喜欢的顺序。如果您想以不同的顺序声明它们,这会有所帮助。

public enum SomeAction
{
    Read = 1,
    Create = 3,
    Update = 2, // Update should come before Create in my list, so I give it a lower value
// ...

如果您想按组对操作进行排序,您可以使用这种手动分配技术来分配重复值(可能是Archive = 1Update = 1)。

现在您已经有了比较列表中项目的基础,有几种方法可以确保它们是有序的:

只需排序

确保约束的一个好方法是自己完成工作。排序它,它就会被排序:)

这只适用于if your sorting function produces a stable sortdocumentation on MSDN says OrderBy does stable sorting 所以你用这个方法就好了。

只有在您有能力重新订购列表中的项目时,它才会起作用。从您的操作的定义(每个操作都依赖于先前状态的操作列表)来看,我不确定这是不是真的。您可能需要选择其他方法之一来检查订单。

var sortedList = yourList.OrderBy(item => (int)item.Action).ToList();

将列表与自身的排序版本进行比较

如果您正在进行错误检查,但不想更正错误,这很有用。

此方法不会更改列表,因此对于您正在查看的操作类型可能是安全的。

var sortedList = yourList.OrderBy(item => (int)item.Action);
bool isSorted = Enumerable.SequenceEqual(yourList, sortedList);

手动编写比较算法

如果您需要严格控制内存分配和 CPU 使用率,这可能很有用。

您可能不需要这种级别的控制,除非您的列表非常大,或者您正处于高性能代码的紧密循环中(例如视频游戏绘制循环)。即使在这些情况下,您也可能需要考虑重构代码,以便此检查不会处于紧密循环的中间(如果可能的话)。

关于为什么我使用for 而不是foreach,请参阅 - In .NET, which loop runs faster, 'for' or 'foreach'?

// Note that you have to build a custom type for your list items to keep high performance,
// or write this inline instead of as a function, to avoid the perf hit of IList<dynamic>
bool IsMySpecificListTypeSorted(List<MyCustomListItemType> theList) {
    int previousOrdinal = -1;

    // Not using foreach because it is "8x slower" in tests
    // and you're micro-optimizing in this scenario
    for(int index = 0; index < theList.Count; ++index) {
        var item = theList[index];
        var currentOrdinal = (int)item.Action;

        if(currentOrdinal < previousOrdinal) {
            return false;
        }

        previousOrdinal = currentOrdinal;
    }

    return true;
}

【讨论】:

    【解决方案2】:

    如果我理解正确,您想按枚举中的项目顺序排序吗?

    如果确实如此,那么您可能知道枚举项具有 int 值。 考虑到这一点,您可以这样订购:

    List<dynamic> demo = new List<dynamic>();
    demo.Add(new { Name = "name1", Action = SomeAction.Read, Value = "someValue" });
    demo.Add(new { Name = "name1", Action = SomeAction.Restore, Value = "someValue" });
    demo.Add(new { Name = "name1", Action = SomeAction.Update, Value = "someValue" });
    
    demo = demo.OrderBy(e => (int)e.Action).ToList();
    

    编辑 我同意这很可能不是正确的方法。基于枚举排序。 OP 可能想要完全改变方法。

    【讨论】:

    • 但是Dictionary&lt;SomeAction, int&gt; 会好很多。您也没有返回布尔值,OP 想知道订单是否正确。
    • 谢谢安德烈,我已经有了一个按动作对它们进行排序的函数。我需要测试它是否已正确订购。
    • @user2928010:请注意,这是一种非常糟糕的方法。如果枚举的实现将来会发生变化怎么办?你甚至没有自己分配一个号码。如果其他人分配数字并且不知道其他一些逻辑依赖于它怎么办?您可以分配一个自定义EnumOrder-attribute。但在我看来,使用另一个集合进行排序要好得多。例如Dictionary&lt;SomeAction, int&gt; ActionOrder。然后你会得到它与var seq = list.OrderBy(x=&gt;ActionOrder[x.Action])
    • 使用bool ordered = list.SequenceEqual(seq) 进行检查。
    【解决方案3】:

    我会这样做,使用Zip linq 扩展

    var inorder= Enum.GetNames(typeof(SomeAction))
            .Zip(array,(x,y) => y.Contains(x))      // change this condition to get uniqueness. 
            .All(x=>x);
    

    查看Demo

    【讨论】:

      【解决方案4】:

      如果您有正确排序的 SomeAction 项目,则只需排序和比较:

        List<MyType> list = ...
      
        var orderedRight = list
          .OrderBy(item => (int) (item.Action))
          .Select(item => item.Action);
      
        boolean inCorrectOrder = list.SequenceEqual(orderedRight
         .Select(item => item.Action));
      

      如果要使用任意顺序,添加mapping

        Dictionary<SomeAction, int> map = new Dictionary<SomeAction, int>() {
          {SomeAction.Read, 2},
          {SomeAction.Create, 1}, // Create should be 1st
          {SomeAction.Update, 2}, // Read and Update considered interchangeable
          ...
          {SomeAction.Create, 15},
        };
      
        ...
      
        var orderedRight = list
          .OrderBy(item => map[item.Action])
          .Select(item => item.Action);
      
        boolean inCorrectOrder = list.SequenceEqual(orderedRight
         .Select(item => item.Action));
      

      【讨论】:

        【解决方案5】:

        您可以为您的枚举分配特定值,然后按如下方式实现 IComparable

        public class TestObj : IComparable<TestObj>
        {
            public string Name { get; set; }
            public SomeAction Action { get; set; }
            public string Value { get; set; }
        
            public TestObj(string name, SomeAction action, string value)
            {
                Name = name;
                Action = action;
                Value = value;
            }
        
            public enum SomeAction
            {
                Read = 0,
                Create = 1,
                Update = 2,
                Delete = 3,
                Download = 4,
                Archive = 5,
                Restore = 6
            }
        
            public override string ToString()
            {
                return string.Format("Name: {0}, Action: {1}, Value: {2}", Name, Action.ToString(), Value);
            }
        
            public int CompareTo(TestObj obj)
            {
                return this.Action.CompareTo(obj.Action);
            }
        }
        

        如下创建一个列表并排序,以正确的顺序输出

               List<TestObj> objs = new List<TestObj>();
               objs.Add(new TestObj("1", Form1.SomeAction.Delete));
               objs.Add(new TestObj("2", Form1.SomeAction.Archive));
               objs.Add(new TestObj("3", Form1.SomeAction.Read));
               objs.Add(new TestObj("4", Form1.SomeAction.Update));
               objs.Add(new TestObj("5", Form1.SomeAction.Create));
        
               objs.Sort();
        
               foreach (var item in objs)
               {
                   Console.WriteLine(item.ToString());
               }
        

        【讨论】:

          【解决方案6】:

          假设 'items' 是您的项目数组,请使用以下方法:

          Enumerable.Range(1, items.Length - 1)
              .All(i => (int)(items[i - 1].Action) < (int)(items[i].Action));
          

          【讨论】:

            【解决方案7】:

            您可以使用简单的 for 循环来检查条件是否满足。

            var enums = Enum.GetValues(typeof(SomeAction)).Cast<SomeAction>();
            for (int i = 0; i < list.Count; i++)
            {
                var listAction = list.ElementAt(i).Action;
                var indexEnumAction = (SomeAction)i;
                Console.WriteLine("{0} == {1} ? {2}", listAction, indexEnumAction, listAction == indexEnumAction);
            }
            

            输出:

            Read == Read ? True
            Create == Create ? True
            Update == Update ? True
            Delete == Delete ? True
            Archive == Download ? False
            

            最快的方法:

            var enums = Enum.GetValues(typeof(SomeAction)).Cast<SomeAction>();
            for (int i = 0; i < list.Count; i++)
            {
                if (list.ElementAt(i).Action != (SomeAction)i)
                {
                    return false;
                }
            }
            return true;
            

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 2017-08-07
              • 1970-01-01
              • 1970-01-01
              • 2016-12-03
              • 2013-08-28
              • 1970-01-01
              • 2019-05-25
              • 1970-01-01
              相关资源
              最近更新 更多