我有一个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();
}
}
答案 0 :(得分:0)
首先,为什么要捕获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();
}
}
答案 1 :(得分:0)
你的SortedSet
是错误的做法。您可以在Comparator
中看到,当两个值都必须通过相同的键查找时,它会变得有点混乱,那么您就会遇到这个混乱(并且不正确)return res != 0 ? res : 1
(1
应该是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
在这种情况下更为常见。)
答案 2 :(得分:0)
你使用迭代器做了很多工作,调用toString(),然后拆分结果。而你的比较器也是额外的工作。保持两侧的Map - 您可以更直接地使用keys()和values(),并让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());
}
现在,迭代inverseMap以打印结果。请注意,如果计数在originalMap中确实存在两次,则只打印一个,这就是您想要的。但是哪一个被打印出来作为读者的练习:-)。您可能希望对此更加具体。
编辑添加:如果你做想要打印出重复的分数,那么不是你想要的。我读过的原帖如果相同就说要跳过,但是在编辑后我没有看到,所以我不确定这是否是OP想要的。