【问题标题】:Java comparator with relative distance具有相对距离的 Java 比较器
【发布时间】:2015-02-14 23:31:33
【问题描述】:

我正在尝试创建一个使用相对距离比较的有序地图。但是,ConcurrentSkipListMap(这是我目前正在使用的)解释来自 Comparator 的比较的方式使得比较相对距离变得不可能。是否有任何数据结构允许像键值操作和相对排序这样的映射?

当我说相对比较时,我的意思是两个值不能直接比较,而必须用一个参考点来看待。像欧几里得距离一样思考。

编辑:

例如:当比较二进制数 0011 和 1100 时,我想说一个大于另一个基于汉明距离(两个数字的异或中的 1 位的数量,相当于超立方体中两个节点之间的距离图),显然我需要一个参考点来比较距离,所以我选择0000作为参考。从0011到0000的距离是2,从1100到0000的距离是2,但是1100不等于0011。我想说它们的相对距离相同,但不相等。最终将生成这些数字的排序列表。对于参考 0000,按升序排列,我们可能有 1000、0100、1100、1001、0011、1110、1101、1111。

EDIT2,为什么我不能使用比较器:

这个总订单的商是: {(x, y) 使得 c.compare(x, y) == 0}。

从 compare 的契约中可以直接得出,商是 S 上的等价关系,并且强加的排序是 S 上的全排序。当我们说 c 强加在 S 上的排序与 equals 一致时,我们表示排序的商是由对象的 equals(Object) 方法定义的等价关系: {(x, y) 使得 x.equals(y)}。

http://docs.oracle.com/javase/7/docs/api/java/util/Comparator.html

【问题讨论】:

  • 示例输入和输出会有所帮助。
  • 您能否发布一些代码来显示您正在尝试做的事情,即使它不起作用?或者 khelwood 所说的示例输入和输出。
  • 为什么需要建立这样的排序?不同的数据结构,例如4-d tree,是否更适合您的目的?如果您正在使用可能比排序列表更有意义的 4 维几何图形。
  • 我不是数学群论方面的专家。但是我对您的引用的理解是,比较器的等价组是由在进行比较时都导致 0 的项目定义的。我看不出这是如何排除使用这种类型的比较器的——只要比较器的行为是固定的。事实上,它经常用于编码,所以我怀疑你误解了文档。
  • “我想说它们的相对距离相同,但不相等。” 然后你需要决定一些其他指标来比较它们时距离相等。

标签: java dictionary data-structures distance comparator


【解决方案1】:

您始终可以通过在距离相同时进行进一步比较来区分与参考编号具有相同距离的实例。例如,假设您将数字表示为Integers:

    public int compare(Integer i1, Integer i2) {
        Integer r1 = hammingDistanceToReference(i1);
        Integer r2 = hammingDistanceToReference(i2);

        if (!r1.equals(r2))
            return r1.compareTo(r2);

        return i1.compareTo(i2);
    }

这样,与参考具有不同汉明距离的数字将被正确排序,而具有相同汉明距离的数字也将被完全排序。

【讨论】:

  • 我考虑过这种方法,但我想看看我是否可以避免它,除非真的需要它。
  • 鉴于这可能是最干净和最简单的方法,我不确定您要避免什么...
  • 还有Comparator.comparingInt(Integer::bitCount).thenComparing(Integer::compareTo)
  • 是的,Java 8 太棒了……还不熟悉它(仍然坚持使用 Java 1.6);但在当前基本比较器由参考编号参数化的情况下,它不会真正起作用。
  • @FrédéricDumont 我想避免使用距离比较器来指示一个点比另一个点更近,但事实并非如此。我只是要添加一个开关来启用或禁用进一步的比较,这样我就可以在需要时使用它们进行排序,或者在我需要知道距离是否真的相等时不使用它们。
【解决方案2】:

几个Set 实现允许比较器与equals 不一致。如果ConcurrentSkipListMap 没有,那么您的选择是使用有的集合或使用无序集合,然后在插入时使用Collection.sort 手动对其进行排序。

下面是一个创建Comparator的例子(与equals不一致):

class Point {
    int distanceTo(Point other) {
        ...
    }

    Comparator<Point> distanceComparator() {
        return (point1, point2) -> distanceTo(point1) - distanceTo(point2);
    }
}

List<Point> points;
Point fixedPoint;
Collections.sort(points, fixedPoints.distanceComparator());

现在这将按照与fixedPoint 的距离对points 进行排序。或者,出于效率原因,您可以在添加新项目时使用集合已经排序以插入正确位置的事实:

您参考了Comparator 的文档,特别是关系的群论定义。关键条件是,如果两个项目是equals,那么它们在比较时必须返回 0。然而,相反的情况肯定不是这样:如果两个项目在比较时返回 0,这并不一定意味着它们是 equals。在很多情况下,两个项目的顺序是不确定的。一个简单的例子是字典排序忽略大小写。在这种情况下,单词“Foobar”、“foobar”和“FOOBAR”就顺序而言都是“相等的”。

这在文档中被称为“与 equals 不一致”。例如,SortedSet 的文档说:“排序集的行为是明确定义的,即使它的顺序与 equals 不一致;它只是不遵守 Set 接口的一般约定。” Set 的所有实现并非如此。

【讨论】:

  • 我最初使用的是比较器,但是正如我提到的比较器的合同不允许这种类型的事情(在我的情况下,尝试使用 ConcurrentSkipListMap)。
  • 我不是数学群论方面的专家。但是我对您的引用的理解是,比较器的等价组是由在进行比较时都导致 0 的项目定义的。或者在我的示例中,点与固定点的距离相等。我看不出这是如何排除使用这种类型的比较器的。事实上,它经常用于编码,所以我怀疑你误解了文档。
  • 我也不是群论专家,但简单地说 compare(x,y) 意味着 x.equals(y),如果 x 实际上不等于 y 并且我有不允许重复键的映射,那么我遇到了问题。
  • @kag0 我假设你的意思是compare(x, y) == 0 暗示x.equals(y)?我不同意 - 我认为这根本不意味着,我认为您不会在文档中的任何地方找到它。正确的是x.equals(y) 暗示compare(x,y) == 0。但对于我在回答中给出的示例来说,这当然是正确的:点到固定点的距离与同一点到同一固定点的距离之差为 0。
  • @kag0 没有强制比较器必须与 equals 一致。这不是合同的一部分。这是一个推荐,因为 Map 和 Set 接口规范是使用 equals 记录的。再次阅读文档。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-09-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多