【问题标题】:Order object by enum in custom order按自定义顺序按枚举排序对象
【发布时间】:2017-12-04 21:16:04
【问题描述】:

我正在尝试按中、大、小的顺序重新排列动物列表。我一直在尝试使用 IComparable.CompareTo 来做到这一点,但我不知道如何以这种特定方式订购它。我只能找到按升序或降序值排序的方法。

我的枚举:

public enum AnimalSize
    {
        Small = 1, Medium = 3, Large = 5,
    }

我的动物课:

public class Animal : IComparable<Animal>
{
    public bool IsCarnivore;
    public AnimalSize Size;

    public Animal(bool isCarnivore, AnimalSize size)
    {
        this.IsCarnivore = isCarnivore;
        this.Size = size;
    }

    public int CompareTo(Animal other)
    {
        return this.Size.CompareTo(other.Size);
    }

我从另一个类中调用 CompareTo,在该类中我有一个私人动物列表。

如何按中、大、小的顺序排列动物?

【问题讨论】:

  • 只是一个愚蠢的问题,但是你为什么不改变enum AnimalSize 让它反映你想要的顺序呢? :Small = 3, Medium = 1, Large = 2,
  • @MongZhu 这不是很反直觉吗?还有一点“锁定”。如果支持不同的排序怎么办?
  • @Fildor 听起来很合理......锁定它会是:)
  • 您会接受不使用IComparable 的答案,还是这是一个固定要求?

标签: c#


【解决方案1】:

我不会为动物等非标量对象实现IComparable&lt;T&gt;。如果你想按高度而不是大小排序怎么办?还是按名字? IComparable 表示对象可以转换为一维量。

相反,在数组中定义您需要的排序顺序,并使用简单的 LINQ 查询进行排序。

public static void Main()
{
    var sampleData = new List<Animal>
    {
        new Animal(false, AnimalSize.Small),
        new Animal(false, AnimalSize.Large),
        new Animal(false, AnimalSize.Medium)
    };

    AnimalSize[] customSortOrder = new[]
    {
        AnimalSize.Small,
        AnimalSize.Medium,
        AnimalSize.Large
    };

    var results = sampleData.OrderBy( a => Array.IndexOf(customSortOrder, a.Size ));

    foreach (var a in results)
    {
        Console.WriteLine(a.Size);
    }

输出:

Small
Medium
Large

Code on DotNetFiddle

【讨论】:

    【解决方案2】:

    您可以创建一个自定义Comparer&lt;Animal&gt;

    public class AnimalSizeComparer : Comparer<Animal>
    {
        private readonly IList<AnimalSize> _order;
    
        public AnimalSizeComparer():this(Enum.GetValues(typeof(AnimalSize)).Cast<AnimalSize>().ToArray())
        {
        }
        public AnimalSizeComparer(IList<AnimalSize> order)
        {
            _order = order;
        }
    
        public override int Compare(Animal x, Animal y)
        {
            if (x == null && y == null) return 0;
            if (x == null) return -1;
            if (y == null) return 1;
    
            return _order.IndexOf(x.Size).CompareTo(_order.IndexOf(y.Size));
        }
    }
    

    您以这种方式使用您的样品订单对其进行初始化:

    var comparer = new AnimalSizeComparer(new[] { AnimalSize.Medium, AnimalSize.Large, AnimalSize.Small });
    yourAminalList.Sort(comparer);
    

    【讨论】:

      【解决方案3】:

      如果要使用 IComparable,则需要先转换为 int。

      public int CompareTo(Animal other)
              {
                  return ((int)this.Size).CompareTo((int)other.Size);
              }
      

      通过此更改,调用包含动物对象的列表的 Sort() 函数将按预期工作。

      【讨论】:

      • 这不会改变顺序。小
      【解决方案4】:

      您可以在比较之前检查它们中的任何一个是否为中等(未测试):

      public int CompareTo(Animal other)
      {
          if (this.Size == other.Size) return 0;
          if (this.Size == AnimalSize.Medium) return -1;
          if (other.Size == AnimalSize.Medium) return 1;
      
          return this.Size.CompareTo(other.Size);
      }
      

      在没有分支错误预测的情况下效率更高(3 变为 1、5 ⇒ 3 和 1 ⇒ 7):

      public int CompareTo(Animal other) => ((int)this.Size + 2 ^ 4) - ((int)other.Size + 2 ^ 4);
      

      或查找数组(3 ⇒ 1、5 ⇒ 2 和 1 ⇒ 3):

      byte[] order = { 0, 3, 0, 1, 0, 2 };
      
      public int CompareTo(Animal other) => order[(byte)this.Size] - order[(byte)other.Size];
      

      【讨论】:

      • @Fildor 现在的顺序是 1, 3 , 5,他希望它是 3 , 5, 1
      • 当我使用这个时,我得到 3,1,5
      猜你喜欢
      • 2020-07-20
      • 2021-06-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多