如何使用比较器对重复的字符串进行排序?

时间:2017-12-14 12:13:40

标签: java sorting queue comparator treemap

假设我有一个包含工人的清单,每个工人有3个字段:名称,他所在的部门(可以只是部门的名称或班级部门的对象)和他的工资。

Elvis       Software Engineering        1000
Samba       Mechanical Engineering      2000
Bamba       Industrial Engineering      3000
Bisli       Medical Engineering         4000
Kinder      Electrical Engineering      1000
Elvis       Software Engineering        9999

现在我想按名字对它们进行排序,并将结果放入队列中。 然后将队列放在地图中,从底部到顶部排序 所以我想要的结果是:

Bamba       Industrial Engineering      3000
Bisli       Medical Engineering         4000
Elvis       Software Engineering        1000
Elvis       Software Engineering        9999
Samba       Mechanical Engineering      2000
Kinder      Electrical Engineering      1000

我不允许使用Collection.sort(),所以我使用比较器按名字对工人进行分类,如果名称相同 - 如果部门对部门进行排序是平等的 - 按薪水排序。 这是我写的比较器:

    class WorkerComparatorByName implements Comparator<Worker<?>> {
    @Override
    public int compare(Worker<?> w1, Worker<?> w2) {
        int compareValue = w1.getName().compareTo(w2.getName());
        if (compareValue != 0)
            return compareValue;
        compareValue = w1.getDepartment().toString().compareTo(w2.getDepartment().toString());
        if (compareValue != 0)
            return compareValue;
        return w1.getSalary() - w2.getSalary();

    }
}

问题是结果如下:

Bamba       Industrial Engineering      3000
Bisli       Medical Engineering         4000
Elvis       Software Engineering        1000
Samba       Mechanical Engineering      2000
Kinder      Electrical Engineering      1000
Elvis       Software Engineering        9999

所有工作人员都已排序,但Elvis(已复制)未排序,它保留在队列的末尾。我尝试用另一个重复的名称替换Elvis,结果相同。 我错过了什么?我怎样才能对重复的值进行排序,以便它们能够一个接一个地排在一起? 这是代码:

    public <T extends Worker<?>> Map<?, ?> createMap(ArrayList<T> list) {
    int i = 1;
    // creating a PriorityQueue sorted by names
    Queue<T> pq = new PriorityQueue<>(new WorkerComparatorByName());
    // filling the PriorityQueue with the workers
    pq.addAll(list);
    Map<Integer, T> treeMap = new TreeMap<Integer, T>();
    // iterating over the PriorityQueue and puting the workers in the map
    for (T element : pq)
        treeMap.put(i++, element);
    return treeMap;
}

3 个答案:

答案 0 :(得分:2)

PriorityQueue API:

方法iterator()中提供的迭代器不保证以任何特定顺序遍历优先级队列的元素。如果需要有序遍历,请考虑使用Arrays.sort(pq.toArray())。

答案 1 :(得分:1)

使用普通的foreach循环和for队列中的项目,而不是使用poll()循环。

// creating a PriorityQueue sorted by names
Queue<T> pq = new PriorityQueue<>(new WorkerComparatorByName());

// filling the PriorityQueue with the workers
pq.addAll(list);

Map<Integer, T> treeMap = new TreeMap<Integer, T>();

int size = pq.size();
for (int j = 0; j < size; j++) {
        treeMap.put(j + 1, pq.poll());
}

答案 2 :(得分:0)

将此问题用作流/ lambda练习,也使用了一些Java 8 comparing好东西。看到你最终使用TreeSet,这是一个很好的解决方案,但无论如何,如果有人有兴趣,我会添加它。

PriorityQueue<Worker> queue =
        new PriorityQueue<>(Comparator.comparing(Worker::getName)
                                    .thenComparing(Worker::getDepartment)
                                    .thenComparing(Worker::getSalary));
queue.addAll(list);

TreeMap<Integer, Worker> treeMap =
        IntStream.range(1, queue.size() + 1)
                .boxed()
                .collect(Collectors.toMap(Function.identity(),
                                          o -> queue.poll(),
                                          (u, v) -> { throw new Error("Will never happen"); },
                                          TreeMap::new));