C# SortedSet<T> 和相等性

15

我对SortedSet的行为有点困惑,以下是一个示例:

public class Blah
{
    public double Value { get; private set; }

    public Blah(double value)
    {
        Value = value;
    }
}

public class BlahComparer : Comparer<Blah>
{
    public override int Compare(Blah x, Blah y)
    {
        return Comparer<double>.Default.Compare(x.Value, y.Value);
    }
}

public static void main()
{
    var blahs = new List<Blah> {new Blah(1), new Blah(2), 
                                new Blah(3), new Blah(2)}

    //contains all 4 entries
    var set = new HashSet<Blah>(blahs); 

    //contains only Blah(1), Blah(2), Blah(3)
    var sortedset = new SortedSet<Blah>(blahs, new BlahComparer());
}

SortedSet会丢弃Compare(x,y)返回0的条目。我能否防止这种情况发生,使我的SortedSet的行为类似于HashSet,并仅在Equals()返回true时丢弃条目?


Comparer的文档确实说0表示“x等于y”,而不是“没有排序”。如果.Value匹配,您也可以比较x和y的引用值。 - Rup
4个回答

10

描述

SortedSet:您需要存储许多元素,并希望以排序顺序存储它们,并从数据结构中消除所有重复项。 SortedSet类型是C#语言和.NET Framework中System.Collections.Generic命名空间的一部分,提供此功能。

根据MSDN,Compare方法返回以下内容:

  • 如果x小于y,则为小于零
  • 如果x等于y,则为
  • 如果x大于y,则为大于零

更多信息

更新

如果您的Bla类实现了IComparable并且您想要对列表进行排序,则可以执行此操作。

var blahs = new List<Blah> {new Blah(1), new Blah(2), 
                            new Blah(3), new Blah(2)};
blahs.Sort();

如果您的Bla类没有实现IComparable接口,而您想要对列表进行排序,您可以使用Linq(System.Linq命名空间)来实现。
blahs = blahs.OrderBy(x => x.MyProperty).ToList();

感谢您勇敢地提出“消除所有重复项”的建议。在实现IComparer时,在返回“0”之前必须要有200%的把握。谢谢。 - ilansch

5
如果值相等,而比较方法本应返回0,则可在提供备用比较时执行此操作。在大多数情况下,这可能只是推迟问题而不是解决问题。正如其他人所指出的那样,SortedSet会丢弃重复项,并在提供自定义比较器时使用该比较器来确定重复性。
    static void Main(string[] args)
    {
        var blahs = new List<Blah>
                        {
                            new Blah(1, 0), new Blah(2, 1),
                            new Blah(3, 2), new Blah(2, 3)
                        };

        blahs.Add(blahs[0]);

        //contains all 4 entries
        var set = new HashSet<Blah>(blahs);

        //contains all 4 entries
        var sortedset = new SortedSet<Blah>(blahs, new BlahComparer());

    }
}

public class Blah
{
    public double Value { get; private set; }

    public Blah(double value, int index)
    {
        Value = value;
        Index = index;
    }

    public int Index { get; private set; }

    public override string ToString()
    {
        return Value.ToString();
    }
}

public class BlahComparer : Comparer<Blah>
{
    public override int Compare(Blah x, Blah y)
    {
        // needs null checks
        var referenceEquals = ReferenceEquals(x, y);
        if (referenceEquals)
        {
            return 0;
        }
        var compare = Comparer<double>.Default.Compare(x.Value, y.Value);
        if (compare == 0)
        {
            compare = Comparer<int>.Default.Compare(x.Index, y.Index);
        }
        return compare;
    }
}

3

你找不到另一个Blah(2)是因为你正在使用一个Set

Set - A collection of well defined and **distinct** objects

MultiSet,例如,允许重复对象。


0
听起来你想要的是基于属性的排序,但重复检查应该基于引用相等性。为了实现这一点(如果您不介意比较器的内存消耗随时间增加),我们可以添加一个回退到比较器,根据实例唯一的ID计算比较结果:
public class BlahComparer : Comparer<Blah>
{
    private readonly ObjectIDGenerator _idGenerator = new();

    public override int Compare(Blah x, Blah y)
    {
        int compareResult = Comparer<double>.Default.Compare(x.Value, y.Value);

        if (compareResult == 0)
        {
            // Comparing hash codes is optional and is only done in order to potentially avoid using _idGenerator further below which is better for memory consumption.
            compareResult =
                Comparer<int>.Default.Compare(RuntimeHelpers.GetHashCode(x), RuntimeHelpers.GetHashCode(y));

            if (compareResult == 0)
            {
                // HashCodes are the same but it might actually still be two different objects, so compare unique IDs:
                compareResult = Comparer<long>.Default.Compare(_idGenerator.GetId(x, out bool _), _idGenerator.GetId(y, out bool _)); // This increases the memory consumption of the comparer for every newly encountered Blah
            }
        }

        return compareResult;
    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接