【问题标题】:Comparison method violates its general contract while sorting比较方法在排序时违反了它的一般合同
【发布时间】:2015-01-27 18:32:17
【问题描述】:

是的,我知道有很多关于同一问题的问题,但我似乎真的找不到我的比较器有什么问题。

所以,这里是:

evaluateComparator = (m1, m2) -> {
    Color color = m1.getColor(); // m1 and m2 will have the same one
    double m1Value, m2Value;
    if (sortingCache.containsKey(m1)) {
        m1Value = sortingCache.get(m1);
    } else {
        // The value has not been computed before so it's not in the cache and I need to compute it now     
        someClass.doSomething(m1);
        m1Value = someClass.getValue();
        someClass.undoSomething(m1);
        sortingCache.put(m1, m1Value);
    }
    if (sortingCache.containsKey(m2)) {
        m2Value = sortingCache.get(m2);
    } else {
        // The value has not been computed before so it's not in the cache and I need to compute it now     
        someClass.doSomething(m2);
        m2Value = someClass.getValue();
        someClass.undoSomething(m2);
        sortingCache.put(m2, m2Value);
    }
    // Since I'm comparing two doubles I can use the Double's comparator
    return Double.compare(m1Value, m2Value);
};

代码非常简单:我需要根据对象对我的主要结构的改变方式对它们进行排序,并且我希望首先获得最高值。

由于计算 m1m2 对象的影响可能需要一些时间,我只是缓存值以便重用它们,所以在排序之前,我检查我是否有缓存值或者是否需要计算它。

一旦我计算出将m1m2 应用于我的结构的结果,我就会将更改还原。

您可以将其视为来自 AI 世界的某种评估排序: 我想根据我应用它们的棋盘分数对这些动作进行排序。

你对此有什么想法吗?

编辑: 由于可能涉及到一些涉及散列和缓存的奇怪事情,我删除了对缓存的所有引用,但我仍然遇到问题。

evaluateComparator = (m1, m2) -> {
    double m1Value, m2Value;

    someClass.doSomething(m1);
    m1Value = someClass.getValue();
    someClass.undoSomething(m1);

    someClass.doSomething(m2);
    m2Value = someClass.getValue();
    someClass.undoSomething(m2);

    return Double.compare(m1Value, m2Value);
};

【问题讨论】:

  • 附带说明,如果您使用 Comparator.comparingDouble() 组合器,您可以用一半的代码实现它。
  • 没用过,能解释一下吗?
  • 您只需提供从一个 Move 对象中提取值的函数。组合器返回完整的两参数比较函数(或者,从技术上讲,是 Comparator 函数接口的实现)。

标签: java sorting


【解决方案1】:

这并不完全算作比较器实现的简单代码。那里可能会出现很多问题,并且没有显示关键代码(doSomethingundoSomething)。从外观上看,m1m2 是可变对象,如果它们发生变化,使得它们与之前的自身不相等,排序算法就会中断。我认为这是对您的错误最可能的解释。

解决您的问题的另一种方法,无论如何我都会推荐,就是重新考虑您的方法。由于任何排序算法必须至少接触每个值一次,因此您的惰性初始化方案只会带来复杂性的开销。而是准备一个简单的 list 移动及其值(您需要一个代表移动及其评估的对象),并且只需使用这个 immutable 对象列表排序它们的自然顺序(compareTo 的简单实现就可以了)。到那时,你的 bug 将几乎没有地方可以隐藏,并且可能在你完成之前就消失了。

【讨论】:

  • m1m2 是可变对象,如果它们发生变化以至于它们不等于之前的自身,排序算法就会中断 你能解释一下吗这个?即使对象的更改不计入getValue 方法,在排序过程中对象是否需要保持不变?
  • 他们的equals 方法是关键(因此hashCode 也是如此,希望它已经正确实现)。这就是用于在缓存中查找的内容。因此,如果情况发生变化,每次您向地图询问另一个键时,它没有。如果此时getValue 返回其他内容,则排序顺序已更改。请注意,必须有 something 会更改比较顺序,因为这是(AFAIK)获得异常的唯一方法。
  • equalshashCode 都没有使用在 doSomething 方法中更改的任何内容,这就是情况很奇怪的原因:\
  • 我已经编辑了这个问题,因为即使删除了对缓存的任何引用,我仍然遇到问题
  • 您还应该从比较器方法中删除值计算。
猜你喜欢
  • 1970-01-01
  • 2015-10-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多