简体   繁体   English

通过将属性与枚举进行比较,C#检查表的顺序正确

[英]C# Check List is in correct order by comparing property to enum

I have a list of objects being returned and I need to check that they are returned in the correct order by one of the properties (as defined in enum). 我有一个返回的对象列表,我需要检查它们是否通过属性之一(如枚举中定义的)以正确的顺序返回。

To give a better example. 举一个更好的例子。 Say I have a List() which contains the following 说我有一个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 }

and the enum contains the following: 枚举包含以下内容:

public enum SomeAction
{
    Read,

    Create,

    Update,

    Delete,

    Download,

    Archive,

    Restore
}

Is there a way I can compare against the enum to check list is ordered correctly by the Action property? 有没有一种方法可以与枚举进行比较,以检查Action属性是否正确地排列了清单?

One thing to note is that the list may not contain objects with properties for all the actions defined in the enum, so a list may just have read/write/delete properties etc. 需要注意的一件事是,列表可能不包含具有枚举中定义的所有动作的属性的对象,因此列表可能仅具有读/写/删除属性等。

If I understand you correctly you want to order by the order of items in your enum right? 如果我对您的理解正确,那么您想按枚举中的项目顺序排序吗?

If that's indeed the case then you probably know the enum items have an int value. 如果确实如此,那么您可能知道枚举项具有int值。 With this in mind you could order it like this : 考虑到这一点,您可以像这样订购它:

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();

Edit I do agree that this is more than likely not the right way to it. 编辑我确实同意,这很可能不是正确的方法。 Ordering based on an enum. 根据枚举排序。 The OP might want to change the approach completely. OP可能希望完全改变方法。

Enums can have an integer value (some might call it an "ordinal") assigned to them. 枚举可以有一个整数值(有人称它为“普通”)。 You can get this integer value by casting. 您可以通过强制转换获得此整数值。

int valueOfEnum = (int)SomeEnum.SomeEnumValue;

In your case, you haven't assigned the integer values, which is just fine. 在您的情况下,您尚未分配整数值,这很好。 If you don't assign them, then C# will automatically assign them for you. 如果您不分配它们,则C#将自动为您分配它们。 They start at 0 , and increment from there. 它们从0开始,从那里开始递增。

Here's the MSDN documentation on using these enum "values" . 这是有关使用这些枚举“值”的MSDN文档

You can put the items in your enum SomeAction definition in the order you want them to occur, and let C# assign the values automatically. 您可以按照希望它们出现的顺序将它们放入enum SomeAction定义中,然后让C#自动分配值。 This might be all that you need to do. 这可能就是您所要做的。

You could also assign values to each of them that specify the order that you prefer. 您还可以为每个值分配值,以指定所需的顺序。 This can help if you want to declare them in a different order. 如果您要以其他顺序声明它们,则可以提供帮助。

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

If you want to sort actions by groups, you could use this manual assignment technique to assign duplicate values (perhaps Archive = 1 and Update = 1 ). 如果要按组对操作进行排序,则可以使用此手动分配技术来分配重复值(也许Archive = 1Update = 1 )。

Now that you have a basis for comparing items in your list, there are a few ways to go about ensuring that they are in order: 现在您已经有了比较列表中项目的基础,有几种方法可以确保它们顺序正确:

Just sort it 整理一下

A great way to ensure a constraint is to do the work yourself. 确保约束的好方法是自己完成工作。 Sort it, and it will be sorted :) 排序,它将被排序:)

This will only work if your sorting function produces a stable sort . 当您的排序功能产生稳定的排序时,此方法才有效。 The documentation on MSDN says OrderBy does stable sorting so you're fine if you use this method. MSDN上文档说OrderBy稳定的排序,因此,如果使用此方法,则可以。

It will also only work if you can afford to re-order the items in your list. 如果您有能力重新订购列表中的商品,它也将起作用。 Judging by the definition of your actions (a list of actions that are each dependent on previous state), I am not sure this is true. 从您的动作的定义(每个动作都依赖于先前状态的列表)来看,我不确定这是真的。 You might need to pick one of the other methods for checking order. 您可能需要选择其他方法来检查订单。

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

Compare the list to a sorted version of itself 将列表与自身的排序版本进行比较

This is useful if you are doing error checking, but don't want to correct the error. 如果您要进行错误检查,但又不想更正错误,这将很有用。

This method won't change the list, so it is probably safe for the type of actions you're looking at. 此方法不会更改列表,因此对于您要查看的操作类型而言,它可能是安全的。

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

Write a comparison algorithm manually 手动编写比较算法

This may be useful if you need to tightly control the memory allocation and CPU usage. 如果您需要严格控制内存分配和CPU使用率,这可能会很有用。

You probably don't need this level of control unless your list is really big, or you're in the middle of a tight loop in high performance code (like a video game draw loop). 除非您的列表很大,否则您可能不需要此控制级别,或者您处于高性能代码的紧密循环中(如视频游戏绘制循环)。 Even in those cases, you may want to consider refactoring the code so this check isn't in the middle of a tight loop, if it is possible. 即使在这种情况下,您也可能要考虑重构代码,以使此检查(如果可能)不在紧迫的循环之中。

For why I used for instead of foreach , see - In .NET, which loop runs faster, 'for' or 'foreach'? 关于为什么我用for代替foreach ,请参见- 在.NET中,哪个循环运行更快,是“ for”还是“ 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;
}

I would do this, using Zip linq extension 我会使用Zip linq扩展名来执行此操作

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

Check this Demo 检查这个Demo

If you have items of the SomeAction ordered right, then just sort and compare: 如果您已SomeAction订购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));

If you want to use arbitrary order, add 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));

You could assign specific values to your enums then implement IComparable as follows 您可以为枚举分配特定的值,然后按如下方式实现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);
    }
}

Creating a list as follows and sorting, outputs in the correct order 如下创建列表并排序,以正确的顺序输出

       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());
       }

Suppose 'items' is the array of your items, use the following approach: 假设“项目”是您的项目的数组,请使用以下方法:

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

You can use a simple for loop to check the conditions are met. 您可以使用简单的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);
}

Output: 输出:

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

Fastest way: 最快的方法:

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;

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM