如何对树图进行排序并显示其值和值的索引,如果上一个索引与下一个索引相同,还可以跳到下一个



我有一个TreeMap,其中存储了一些值。使用从最高到最低的值对地图进行排序。现在我想打印出TreeMap的内容及其各种索引。

如果我在地图上有以下配对:

("Andrew", 10),
("John", 5),
("Don",9),
("Rolex", 30),
("Jack", 10),
("Dan",9)

我想打印出来:

Rolex, 30 , 1
Jack, 10, 2
Andrew, 10, 2
Dan, 9, 4
Don, 9, 4
John, 5, 6.

这是我一直在尝试的,但似乎效果不佳:

/**
 *
 * @author Andrew
 */
import java.util.*;
public class SortArray {
    static <K,V extends Comparable<? super V>> SortedSet<Map.Entry<K,V>>entriesSortedByValues(Map<K,V> map) {
        SortedSet<Map.Entry<K,V>> sortedEntries = new TreeSet<Map.Entry<K,V>>(
                new Comparator<Map.Entry<K,V>>() {
                    @Override public int compare(Map.Entry<K,V> e1, Map.Entry<K,V> e2) {
                         int res = e1.getValue().compareTo(e2.getValue());
                        return res!= 0 ? res : 1;
                        //return e1.getValue().compareTo(e2.getValue());
                    }
                });
        sortedEntries.addAll(map.entrySet());
        return sortedEntries;
    }

    public void test(){
        Map mm = new TreeMap();
        mm.put("Andrew", 11);
        mm.put("Mbata", 21);
        mm.put("Chinedu", 14);
        mm.put("Bol", 14);
        mm.put("Don", 51);
        mm.put("Rolex", 16);
        mm.put("Son", 41);
        SortedSet newMap =  entriesSortedByValues(mm);
        Iterator iter = newMap.iterator();
        int x = newMap.size();
        List names = new ArrayList();
        List scores = new ArrayList();
        while(iter.hasNext()){
            String details = iter.next().toString();
            StringTokenizer st = new StringTokenizer(details, "=");
            String name = st.nextToken();
            names.add(name);
            String score = st.nextToken();
            scores.add(score);
            //System.out.println(name + " Score:" +score + " Position:" + x);
            x--;
        }
        Collections.reverse(names);
        Collections.reverse(scores);
        int pos = 1;
        for(int i = 0; i<names.size();){
            try{
                int y = i+1;
                if(scores.get(i).equals(scores.get(y))){
                    System.out.print("Name: "+ names.get(i)+"t");
                    System.out.print("Score: "+ scores.get(i)+"t");
                    System.out.println("Position: "+ String.valueOf(pos));
                    //pos++;
                    i++;
                    continue;
                } else{
                    System.out.print("Name: "+ names.get(i)+"t");
                    System.out.print("Score: "+ scores.get(i)+"t");
                    System.out.println("Position: "+ String.valueOf(pos++));
                }
                i++;
            } catch(IndexOutOfBoundsException e) {}
        }
    }
    public SortArray(){
        test();
    }
    public static void main(String [] args){
        new SortArray();
    }
}

首先,为什么要捕获IndexOutOfBoundsException,却什么都不做?如果你运行它,你会抛出异常(我想你已经知道了),问题出在最后一个"for"循环中的算法中。我不应该给你解决方案,但是。。。至少你做了一些努力使它运行,所以这是一个工作较少的版本:

import java.util.*;
public class SortArray {
    static <K,V extends Comparable<? super V>> SortedSet<Map.Entry<K,V>>entriesSortedByValues(Map<K,V> map) {
    SortedSet<Map.Entry<K,V>> sortedEntries = new TreeSet<Map.Entry<K,V>>(
            new Comparator<Map.Entry<K,V>>() {
                @Override public int compare(Map.Entry<K,V> e1, Map.Entry<K,V> e2) {
                    int res = e1.getValue().compareTo(e2.getValue());
                    return res != 0 ? res : 1;
                    //return e1.getValue().compareTo(e2.getValue());
                }
            });
    sortedEntries.addAll(map.entrySet());
    return sortedEntries;
    }
    public void test(){
    Map mm = new TreeMap();
    mm.put("Andrew", 11);
    mm.put("Mbata", 21);
    mm.put("Chinedu", 14);
    mm.put("Bol", 14);
    mm.put("Don", 51);
    mm.put("Rolex", 16);
    mm.put("Son", 41);
    SortedSet newMap =  entriesSortedByValues(mm);
    Iterator iter = newMap.iterator();
    int x = newMap.size();
    List names = new ArrayList();
    List scores = new ArrayList();
    while(iter.hasNext()){
        String details = iter.next().toString();
        StringTokenizer st = new StringTokenizer(details, "=");
        String name = st.nextToken();
        names.add(name);
        String score = st.nextToken();
        scores.add(score);
        //System.out.println(name + " Score:" +score + " Position:" + x);
        x--;
    }
    Collections.reverse(names);
    Collections.reverse(scores);
    int pos;
    int posBis = 0;
    String lastScore = "";
    for(int i = 0; i<names.size(); i++){
        System.out.print("Name: "+ names.get(i)+"t");
        System.out.print("Score: "+ scores.get(i)+"t");
        if(i == 0 || !lastScore.equals(scores.get(i))) {
            pos = i + 1;
            posBis = pos;
        } else {
            pos = posBis;
        }
        System.out.println("Position: "+ String.valueOf(pos));
        lastScore = (String)scores.get(i);
    }
    }
    public SortArray(){
    test();
    }
    public static void main(String [] args){
    new SortArray();
    }
}

您的SortedSet是错误的做法。您可以在Comparator中看到,当两个值都必须由同一个键查找时,它会变得有点混乱,然后您得到了这个混乱(且不正确)的return res != 0 ? res : 11实际上应该是e1.getKey().compareTo(e2.getKey()),而不是总是返回1)。

一个更好的方法是在List中自己对密钥进行排序,而不是创建一个单独的SortedSet。这样,您就不必担心排序值重复。

如果需要的话,您还可以稍微抽象出Comparator的内容,以便以后在其他代码中更可重用

import java.util.*;
public class PrintSomething {
    public static <T extends Comparable<T>> Comparator<T> reverseComparator(final Comparator<T> oldComparator) {
        return new Comparator<T>() {
            @Override
            public int compare(T o1, T o2) {
                return oldComparator.compare(o2, o1);
            }
        };
    }
    public static <K,V extends Comparable<V>> Comparator<K> keyedComparator(final Map<K,V> lookup) {
        return new Comparator<K>() {
            @Override
            public int compare(K o1, K o2) {
                return lookup.get(o1).compareTo(lookup.get(o2));
            }
        };
    }
    public static void main(String[] args) {
        Map<String, Integer> mm = new HashMap<>();
        mm.put("Andrew", 10);
        mm.put("John", 5);
        mm.put("Don", 9);
        mm.put("Rolex", 30);
        mm.put("Jack", 10);
        mm.put("Dan", 9);
        Comparator<String> comparator = reverseComparator(keyedComparator(mm));
        List<String> keys = Arrays.asList(mm.keySet().toArray(new String[mm.size()]));
        //Collections.sort(keys); // optional, if you want the names to be alphabetical
        Collections.sort(keys, comparator);
        int rank = 1, count = 0;
        Integer lastVal = null;
        for (String key : keys) {
            if (mm.get(key).equals(lastVal)) {
                count++;
            } else {
                rank += count;
                count = 1;
            }
            lastVal = mm.get(key);
            System.out.println(key + ", " + mm.get(key) + ", " + rank);
        }
    }
}

一般来说,当您需要对数据本身进行排序时,像SortedSet这样的东西更有意义。当你只需要一次以有序的方式处理某件事时,它们通常比它们的价值更麻烦。(还有:你使用TreeMap有什么原因吗?TreeMap对它们的键进行排序,但不是按值排序,所以在这种情况下,你没有利用这种排序。在这种情况中,使用HashMap更常见。)

您使用迭代器做了很多工作,调用toString(),然后拆分结果。你的比较器也是额外的工作。两边都使用Map-您可以更直接地使用键()和值(),并让Java为您进行排序。您上面的大部分代码可以替换为:(为了清楚起见,我将您的名称"mm"改为"originalMap")

Map<Integer, String> inverseMap = new TreeMap<Integer, String>();
for (Map.Entry<String, Integer> entry : originalMap.entrySet()) {
  inverseMap.put(entry.getValue(), entry.getKey());
}

现在,在inverteMap上迭代以打印结果。请注意,如果一个计数在originalMap中确实存在两次,则只会打印一次,这正是您想要的。但哪一本被印刷出来作为读者的练习:-)。你可能想更具体一点。

编辑添加:如果确实想要打印出重复的分数,这是而不是您想要的。我读到的原始帖子说,如果它们相同,就跳过,但编辑后我看不到,所以我不确定这是否是OP想要的。

相关内容

最新更新