【问题标题】:NavigableMap - Compare based on valuesNavigableMap - 根据值进行比较
【发布时间】:2018-01-17 08:57:31
【问题描述】:

我正在尝试使用自定义比较器实现 NavigableMap,该比较器基于值而不是键进行比较。我对 Java 和一般编码非常了解,所以如果我的术语不正确或代码很糟糕,请原谅我!我已经尝试找到类似的问题来尝试复制解决方案,但在尝试编译时仍然收到以下错误:

java: no suitable constructor found for TreeMap(OrderLineSegments)
    constructor java.util.TreeMap.TreeMap(java.util.Comparator<? super java.lang.Float>) is not applicable
      (argument mismatch; OrderLineSegments cannot be converted to java.util.Comparator<? super java.lang.Float>)
    constructor java.util.TreeMap.TreeMap(java.util.Map<? extends java.lang.Float,? extends java.lang.Float[]>) is not applicable
      (argument mismatch; OrderLineSegments cannot be converted to java.util.Map<? extends java.lang.Float,? extends java.lang.Float[]>)
    constructor java.util.TreeMap.TreeMap(java.util.SortedMap<java.lang.Float,? extends java.lang.Float[]>) is not applicable
      (argument mismatch; OrderLineSegments cannot be converted to java.util.SortedMap<java.lang.Float,? extends java.lang.Float[]>)

我正在尝试实现以下内容,其中 Float[] 是表示线段的 4 个浮点数 [x1,y1,x2,y2] 的数组。

NavigableMap<Float, Float[]> segmentBST = new TreeMap<Float, Float[]>( new OrderLineSegments() );

class OrderLineSegments implements Comparator<Map.Entry<Float, Float[]>> {
public int compare(Map.Entry<Float, Float[]> a, Map.Entry<Float, Float[]> b) {
    float ypos;
    if (a.getValue()[1] < a.getValue()[1]) {
        ypos = a.getValue()[1];
    } else {
        ypos = b.getValue()[1];
    }
    float ratioA = (a.getValue()[1] - ypos) / (ypos - a.getValue()[3]);
    float ratioB = (b.getValue()[1] - ypos) / (ypos - b.getValue()[3]);
    float posA = Math.abs(a.getValue()[0] - a.getValue()[2]) * ratioA + a.getValue()[0];
    float posB = Math.abs(b.getValue()[0] - b.getValue()[2]) * ratioB + b.getValue()[0];
    if (posA < posB) return 1;
    if (posA > posB) return -1;
    return 0;
}

我什至不确定这是否是最好的方法,或者这是否可能,因此非常感谢任何帮助。

【问题讨论】:

  • Comparator是用来比较keys的,所以OrderLineSegments需要实现Comparator&lt;Float&gt;。因此,当您尝试比较 Map.Entry 时会出现错误。
  • 该错误似乎很正常,正如文档所说:constructor of TreeMap&lt;K,V&gt; requires Comparator&lt;? super K&gt; 并且您提供了Comparator&lt;Entry&lt;K,V&gt;&gt; 它不能像,您不能反转键和值吗?如果你没有相同的值,你可以改变
  • 你违反了 NavigableMap 的合同。在这种情况下,为什么不直接使用排序列表?
  • @Kayaman 我还在学习如何解释 java 文档——现在这似乎很明显了!
  • @daniu 我认为 NavigableMap 是最好的解决方案,因为它带有higherEntry 和lowerEntry(这也在O(ln(n)) 中运行)

标签: java dictionary compare comparator


【解决方案1】:

您可以将比较器创建为带有支持图的单独对象,然后在比较方法中从同一图获取值。在此之后,您可以将逻辑应用于值... 在将内容放入实际的可导航地图之前,您还需要使用带有覆盖的“put”方法的树图扩展,该方法将内容放入支持地图。

类似的东西:

public static void main(String[] args) throws IOException {
    // Sun, 27 Jul 2014 10:19:10 +0100

    class OrderLineSegments implements Comparator<Float> {

        private Map<Float, Float[]> supportMap = new HashMap<>();

        public int compare(Float aKey, Float bKey) {
            Float[] aValue = supportMap.get(aKey);
            Float[] bValue = supportMap.get(bKey);
            float ypos;
            if (aValue[1] < bValue[1]) {
                ypos = aValue[1];
            } else {
                ypos = bValue[1];
            }
            float ratioA = (aValue[1] - ypos) / (ypos - aValue[3]);
            float ratioB = (bValue[1] - ypos) / (ypos - bValue[3]);
            float posA = Math.abs(aValue[0] - aValue[2]) * ratioA + aValue[0];
            float posB = Math.abs(bValue[0] - bValue[2]) * ratioB + bValue[0];
            if (posA < posB) return 1;
            if (posA > posB) return -1;
            return 0;
        }

    }

    OrderLineSegments orderLineSegments = new OrderLineSegments();

    class ExtendendNavigableMap extends TreeMap<Float, Float[]> {

        private OrderLineSegments orderLineSegments;

        public ExtendendNavigableMap(OrderLineSegments comparator) {
            super(comparator);
            orderLineSegments = comparator;
        }

        @Override
        public Float[] put(Float key, Float[] value) {
            orderLineSegments.supportMap.put(key, value);
            return super.put(key, value);
        }
    }

    NavigableMap<Float, Float[]> segmentBST = new ExtendendNavigableMap(orderLineSegments);

    // Start adding elements
    segmentBST.put(1.0F, new Float[]{0.1f, 0.2f, 0.3f, 0.4f});
    segmentBST.put(1.9F, new Float[]{0.3f, 0.2f, 0.3f, 0.4f});
    segmentBST.put(1.1F, new Float[]{-0.3f, 0.2f, 0.3f, 0.4f});

    segmentBST.forEach((k, v) -> System.out.printf("%s:%s%n", k, Arrays.toString(v)));
}

输出:

1.9:[0.3, 0.2, 0.3, 0.4]
1.0:[0.1, 0.2, 0.3, 0.4]
1.1:[-0.3, 0.2, 0.3, 0.4]

虽然这个解决方案令人费解且丑陋,但它绝对可以工作。使用包含键和值的对象的树集更自然,然后使用您的问题中建议的实现逻辑为其创建自定义比较器。

【讨论】:

  • 谢谢!现在正在编译。虽然地图的顺序似乎不服从比较功能。例如:如果地图已经包含: 1.3283 : [1.3283, 89.719, 5.7766, 70.22] 并且我添加: 3.2011 : [3.2011, 72.564, 14.316, 55.937] 它应该插入到左侧(即较低的位置)并且看起来像: {3.2011 : [3.2011, 72.564, 14.316, 55.937], 1.3283 : [1.3283, 89.719, 5.7766, 70.22]} 但它像这样添加到右侧(上方位置):{1.3283 : [1.3283, 89.719, 576,. 70.22], 3.2011 : [3.2011, 72.564, 14.316, 55.937]}
  • 似乎没有调用比较。我在比较块内放置了一个 println 语句,但没有打印任何内容。我假设这表明它没有被使用并且正在使用自然键排序?我还需要做些什么来实现这个吗?
  • 抱歉,确实是这样。我已经更新了答案。你能再试试这个代码吗?如果它对你有用,请告诉我。
  • 现在调用比较函数但是我在使用lowerEntry和higherEntry时遇到了以下错误:OrderLineSegments.compare(planesweep.java:31)的线程“main”java.lang.NullPointerException中的异常里面比较。在 OrderLineSegments.compare(planesweep.java:22) 里面比较。在 java.util.TreeMap.compare(TreeMap.java:1295) 在 java.util.TreeMap.getLowerEntry(TreeMap.java:494) 在 java.util.TreeMap.lowerEntry(TreeMap.java:700) 在 planesweep.main( planesweep.java:241)
  • 我现在很想看看我如何才能完成这项工作,但我同意这有点失控了!我一直在研究 NavigableSet 并且可能只存储 Float[] 信息就可以逃脱,如果解决这个 NavigableMap 问题太困难,我可以尝试作为替代方案。
猜你喜欢
  • 1970-01-01
  • 2019-04-16
  • 2023-03-25
  • 1970-01-01
  • 1970-01-01
  • 2019-03-26
  • 1970-01-01
  • 1970-01-01
  • 2022-01-25
相关资源
最近更新 更多