使用 Comparer 通过字典中的值来比较键,SortedDictionary 总是抛出异常

With a Comparer to comparer keys by their values from a dictionary, SortedDictionary always throw exception

我想用 SortedDictionary 实现一个堆,它比较值而不是键。我的元素在字典中,我将它们一一添加到 SortedDictionary 中。它总是在第二次从循环中的 "Add" 方法抛出异常。 "An entry with the same key already exists"。 因为我从字典中得到了元素,所以我知道键不能相同。我应该怎么做才能使这样的 SortedDictionary 工作? 非常感谢!

dic = new Dictionary<int, int>();
var sort = new SortedDictionary<int, int>(Comparer<int>.Create((x, y) => dic[x].CompareTo(dic[y])));
foreach (var pair in dic)
{
    sort.Add(pair.Key, pair.Value);
}

您可以尝试下一个方法:

var sort = new SortedDictionary<int, int>(
    Comparer<int>.Create(
        (x, y) => 
        {
            int vx = dic[x];
            int vy = dic[y];

            // If values are the same then compare keys.
            if (vx == vy)
                return x.CompareTo(y);

            // Otherwise - compare values.
            return vx.CompareTo(vy);
        }));

如果您使用此方法声明 sort,则 sort 中的 Keys 将按 Values 排序。 complete sample 展示了这种方法的工作原理。


@SylvainLIU 问:

What confuse me is, in my original post, by using dic[x].CompareTo(dic[y]) I meant to get the return value of the Compare() method, but not to take dic[x] or dic[y] as Key of the SortedDictionary. Why they're asked to be unique?

你是对的,你的样本如你所想的那样工作。那为什么会抛出异常呢?

SortedDictionary 必须包含唯一键。通过为 SortedDictionary 指定 Comparer,我们指定了如何对键进行排序以及如何定义新键是否唯一。如果 Comparer returns 0 为新密钥,则此密钥不是唯一的,将抛出异常 An entry with the same key already exists

如果我们使用比较器 dic[x].CompareTo(dic[y]) 然后比较键 xy 我们使用它们的值 dic[x]dic[y]。例如,让我们有两对 (Key=1, Value=3)(Key=2, Value=3)。如果我们使用比较器 dic[x].CompareTo(dic[y]) 来比较它们,那么这对键不是唯一的,因为它们是通过它们的值 3.CompareTo(3) = 0 进行比较的。当然,值 12 是不同的数字,但是从比较器的角度来看 dic[x].CompareTo(dic[y]) 它们是相同的。因此,如果我们使用这个比较器,我们必须确保对的值必须是唯一的,以防止重复错误。

如果我们使用下一个比较器

int vx = dic[x];
int vy = dic[y];

// If values are the same then compare keys.
if (vx == vy)
    return x.CompareTo(y);

// Otherwise - compare values.
return vx.CompareTo(vy);

那么 dic 的值不能是唯一的,因为这个比较器考虑到 dic 中的值可以是相同的,对于这种情况,它使用另一种策略来排序和检查唯一性。