HashSet按属性排序,但与另一个属性设置为唯一性

时间:2018-10-28 23:16:14

标签: c# hashset

我想知道如何使用SortedSet,可以按对象的一个​​属性进行排序,另一方面可以将Uniity设置为另一个属性。

这是我拥有的:

using System;
using System.Collections.Generic;

namespace ConsoleApp1
{
    class Program
    {
        static void Main(string[] args)
        {
            var bonusSortedSet = new SortedSet<Bonus>(new ComparerByNumber());

        var bonus0 = new Bonus()
        {
            ID = "6479cc32-960d-4aa0-a62d-8c81e65085e8",
            Number = 15
        };

        var bonus1 = new Bonus()
        {
            ID = "8e8a9c1b-1889-4c4c-b039-b1dbe005719b",
            Number = 10
        };

        var bonus2 = new Bonus()
        {
            ID = "3453f78d-ce28-4ab1-a7a1-395063374f87",
            Number = 11
        };

        var bonus3 = new Bonus()
        {
            ID = "8e8a9c1b-1889-4c4c-b039-b1dbe005719b",
            Number = 12
        };

        bonusSortedSet.Add(bonus0);
        bonusSortedSet.Add(bonus1);
        bonusSortedSet.Add(bonus2);
        bonusSortedSet.Add(bonus3);

        foreach (var bonus in bonusSortedSet)
        {
            Console.WriteLine($"{bonus.ID} : {bonus.Number}");
        }
    }
}

public class Bonus : IEqualityComparer<Bonus>
    {
        public string ID { get; set; }

        public int Number { get; set; }

        public bool Equals(Bonus x, Bonus y)
        {
            return x.GetHashCode() == y.GetHashCode();
        }

        public int GetHashCode(Bonus obj)
        {
            return obj != null ? obj.ID.GetHashCode() : string.Empty.GetHashCode();
        }
    }

public class ComparerByNumber : IComparer<Bonus>
{
    public int Compare(Bonus x, Bonus y)
    {
        return Math.Sign(x.Number - y.Number);
    }
}

}

结果是:

  • 8e8a9c1b-1889-4c4c-b039-b1dbe005719b:10
  • 3453f78d-ce28-4ab1-a7a1-395063374f87:11
  • 8e8a9c1b-1889-4c4c-b039-b1dbe005719b:12
  • 6479cc32-960d-4aa0-a62d-8c81e65085e8:15

我会期望的:

  • 8e8a9c1b-1889-4c4c-b039-b1dbe005719b:10
  • 3453f78d-ce28-4ab1-a7a1-395063374f87:11
  • 6479cc32-960d-4aa0-a62d-8c81e65085e8:15

2 个答案:

答案 0 :(得分:1)

您尚未实现任何代码来使Bonus对象的ID属性唯一,而仅使其Number属性唯一。即使您这样做,例如:

public int Compare(Bonus x, Bonus y)
{
    if (x.ID == y.ID) return 0;
    return Math.Sign(x.Number - y.Number);
}

这可以在某些情况下起作用,但是完全由SortedSet<T>的内部实现驱动,并且不太可能在99%的时间内起作用。

您不能让集合按一个属性排序,而唯一性则由另一个属性决定。如果要跟踪两个独立属性的顺序和唯一性,则需要两个集合对象。

答案 1 :(得分:0)

您的课程实现了IEqualityComparer<Bonus>,这是错误的。您不想让奖金成为比较者,而是希望奖金可以平等。

此外,不要通过检查哈希码是否相同来实现Equals。会发生哈希冲突(但使用GetHashCode的情况很少见)。

尝试像这样编写Bonus类型:

public sealed class Bonus
{
    public string ID { get; set; }

    public int Number { get; set; }

    public override bool Equals(object obj)
    {
        if (obj is Bonus other)
        {
            return ID == other.ID;
        }
        return false;
    }

    public override int GetHashCode()
    {
        return ID?.GetHashCode() ?? 0;
    }
}

然后使用隐式(默认)相等比较器创建一个HashSet<>

var bonusSet = new HashSet<Bonus>();

将确保集合成员在ID中是唯一的。然后,您可以在枚举成员时使用Linq对成员进行排序:

foreach (var bonus in bonusSet.OrderBy(x => x.Number))
{
    Console.WriteLine($"{bonus.ID} : {bonus.Number}");
}