【问题标题】:Java Priority Queue Compare String to String[]Java 优先级队列比较字符串和字符串 []
【发布时间】:2022-11-21 05:37:09
【问题描述】:

我对 PriorityQueue 感到困惑,不确定我的用例是否有不同的方法。

我不想比较两个字符串,而是想将传入的字符串与 String[] 进行比较。

它有点工作,但头节点不会移动。

主要的:

public class App 
{
    public static void main( String[] args )
    {
        PriorityString priorityString = new PriorityString();
        
        PriorityQueue<String> priorityQueue = new PriorityQueue<String>(priorityString);
        
        priorityQueue.add("test");
        priorityQueue.add("john");
        priorityQueue.add("blue");
        priorityQueue.add("orange");
        priorityQueue.add("grape");
        priorityQueue.add("handle");
        
        while (!priorityQueue.isEmpty()) {
            System.out.println("Removed: " + priorityQueue.remove());
        } 
    }
}

比较类:

public class PriorityString implements Comparator<String> {
    
    String[] valueStrings;
    
    PriorityString() {
        valueStrings = new String[] {"all", "john", "door", "floor", "record", "desk", "orange"};
    }

    public int compare(String o1, String o2) {
        if (Arrays.asList(valueStrings).contains(o1))
            return 0;
        else
            return 1;
    }

}

结果:

Removed: test
Removed: john
Removed: orange
Removed: blue
Removed: handle
Removed: grape

值“test”始终排在第一位,即使它不在 String[] 中也是如此。 其他值的顺序似乎是正确的,因为“john”和“orange”在 String[] 中,而其余的则不是。

问题是什么,这是实现我的用例的正确方法吗?

编辑:我也试过这个

    public int compare(String o1, String o2) {
        if (Arrays.asList(valueStrings).contains(o1))
            return -1;
        else if (Arrays.asList(valueStrings).contains(o2)) 
            return 0;
        else
            return 1;
    }

结果如下:

Removed: orange
Removed: handle
Removed: grape
Removed: test
Removed: blue
Removed: john

橙色在正确的位置 by john 在底部,当它应该在橙色之后

新编辑:根据评论重新阅读文档后,我设法以这种方式实现了一个工作版本。可能会添加@Progman else 返回。

    public int compare(String o1, String o2) {
        if (Arrays.asList(valueStrings).contains(o1))
            return -1;
        else if (Arrays.asList(valueStrings).contains(o2)) 
            return 1;
        else
            return 0;
    }

结果:

Removed: orange
Removed: john
Removed: grape
Removed: test
Removed: blue
Removed: handle

【问题讨论】:

  • 你的Comparator坏了,请咨询它的documentation(例如“当第一个参数小于、等于或大于第二个参数时,返回负整数、零或正整数。", "实施者必须确保所有 x 和 y 的 signum(compare(x, y)) == -signum(compare(y, x))“,……)

标签: java priority-queue


【解决方案1】:

您的 compare() 方法没有检查两个传入的 String 对象。这使得当您只看一个字符串时很难比较两个字符串。此外,您的 compare() 方法在某种意义上不是对称的,因为 sgn(compare(x,y))-sgn(compare(y,x)) 不同(请注意 -),如 https://docs.oracle.com/javase/8/docs/api/java/util/Comparator.html#compare-T-T- 中所定义。这使得 PriorityQueue 如何在内部对 String 对象进行排序变得非常困难(或不可预测)。

当你想要某种在开头排序的“VIP”String列表时,你必须检查compare(x, y)方法的几种情况:

  • x 是“VIP”值,但y 不是。
  • xy 一样是“VIP”值。
  • x 不是“VIP”值,但 y 是。
  • x 不是“VIP”值,y 也不是。

特别地,当值都是“VIP”值或都不是“VIP”值时,您仍然必须为这些字符串返回一个合理的比较值。该方法是首先处理一个值在“VIP”列表中而另一个不在的情况。之后,使用String.compareTo() 正常比较字符串。该方法可能如下所示:

public int compare(String o1, String o2) {
    if (valueStringsList.contains(o1) &&
        !valueStringsList.contains(o2)) {
        return -1; // only o1 is a "VIP"
    }
    if (!valueStringsList.contains(o1) &&
        valueStringsList.contains(o2)) {
        return 1;  // only o2 is a "VIP"
    }
    return o1.compareTo(o2); // normal sorting
}

(您可能需要交换 1-1

【讨论】:

  • 当我按照提到的@user16320675 重新阅读文档时,我也设法创建了一个工作版本(检查新编辑)。你的也可以!你解释得很好,让我理解了用例。
【解决方案2】:

逻辑关闭了。如果两者都存在或都不存在,则您需要返回 0。这是实现这一目标的一种方法:

public int compare(String o1, String o2) {
    List<String> list = Arrays.asList(valueStrings);
    boolean found1 = list.contains(o1);
    boolean found2 = list.contains(o2);
    return found1 == found2 ? 0 : found1 ? -1 : 1;
}

或者,您可以从 lambda 构造一个比较器,而不是手动实现它:

Comparator.comparing(Arrays.asList(valueStrings)::contains).reversed()

【讨论】:

  • 啊这个更短,但是我对 return 语句很困惑,我不知道你可以在一行中有两个三元运算符。
猜你喜欢
  • 1970-01-01
  • 2013-05-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多