我有一个N个字符串的列表,以及一个N分数的并行列表。我需要使用表中的分数对字符串进行排序。我该怎么做?
我目前的解决方案是使用索引的辅助列表,如下所示:
public static List<String> sortByScores(List<String> strings, final List<Float> scores) {
List<Integer> indices = new ArrayList<Integer>(strings.size());
for (int i=0; i<strings.size(); i++)
indices.add(i);
Collections.sort(indices, new Comparator<Integer>() {
@Override public int compare(Integer arg0, Integer arg1) { // sort in descending order
return -scores.get(arg0).compareTo(scores.get(arg1));
}
});
List<String> sortedStrings = new ArrayList<String>(strings.size());
for (int i=0; i<indices.size(); ++i)
sortedStrings.add(strings.get(indices.get(i)));
return sortedStrings;
}
它有效,但似乎效率低下。
有更好的解决方案吗?
答案 0 :(得分:3)
伪代码
// Precondition: length of each list is the same, call it N
let m = new TreeMap<Integer, List<String>>()
for i in 0 .. N-1
if m.containsKey(scores[i])
m.get(scores[i]).append(strings[i])
else
m.put(scores[i], a new list containing the sole element strings[i])
end if
end if
for each entry (k, v) in m
output all the strings in v
end
无需排序或定义可比对象或任何内容,因为树形图已按分数排序!
答案 1 :(得分:2)
将字符串和分数放入一个类并以这种方式实现Comparable接口,您可以对分数进行排序,但是一旦字符串排序就可以访问它(对我来说似乎最有效)。
示例:
public class ScoreClass implements Comparable<ScoreClass>
{
String myString;
float score;
public int compareTo(ScoreClass c)
{
return Float.compare(this.score, c.score);
}
}
这是脑编译的代码,所以如果出现问题请告诉我。
答案 2 :(得分:2)
我创建一个包含String及其得分的新POJO,并让它实现Comparable
答案 3 :(得分:0)
好的,我使用随机的字符串集测试了你建议的所有方法:
public static void testSortByScores(int count) {
int length = 4;
// Create a random array and random scores:
List<String> strings = new ArrayList<String>(count);
List<Float> scores = new ArrayList<Float>(count);
RandomString randomString = new RandomString(length);
String letters = "abcdefghijklmnopqrstuvwxyz";
for (int iString=0; iString<count; ++iString) {
StringBuffer randomStringBuffer = new StringBuffer(length);
int score = 0;
for (int iChar=0; iChar<length; ++iChar) {
int index = (int)(Math.random()*letters.length());
char c = letters.charAt(index);
randomStringBuffer.append(c);
score += index;
}
strings.add(randomStringBuffer.toString());
scores.add((float)score);
}
long start = System.currentTimeMillis();
strings = sortByScoresUsingIndices(strings,scores);
//strings = sortByScoresUsingClass(strings,scores);
//strings = sortByScoresUsingTree(strings,scores);
System.out.println("sorting "+count+" took "+(System.currentTimeMillis()-start)+" ms.");
}
以下是结果:
我的方法 - sortByScoresUsingIndices - 可能更糟糕:
sorting 10000 took 52 ms.
sorting 30000 took 140 ms.
sorting 100000 took 396 ms.
sorting 300000 took 382 ms.
sorting 1000000 took 1122 ms.
sorting 3000000 took 5096 ms.
然后是使用ScoreClass的方法,我实现如下:
public static List<String> sortByScoresUsingClass(List<String> strings, final List<Float> scores) {
List<ScoreClass> list = new ArrayList<ScoreClass>(strings.size());
for (int i=0; i<strings.size(); i++) {
ScoreClass sc = new ScoreClass(strings.get(i),scores.get(i));
list.add(sc);
}
Collections.sort(list);
List<String> sortedStrings = new ArrayList<String>(strings.size());
for (ScoreClass item: list)
sortedStrings.add(item.myString);
return sortedStrings;
}
sorting 10000 took 60 ms.
sorting 30000 took 121 ms.
sorting 100000 took 40 ms.
sorting 300000 took 280 ms.
sorting 1000000 took 648 ms.
sorting 3000000 took 3254 ms.
,最好的一个是使用TreeMap的方法,但我不得不更改它并使用一个列表,因为可能有多个字符串具有相同的分数:
public static List<String> sortByScoresUsingTree(List<String> strings, final List<Float> scores) {
TreeMap<Float,List<String>> treeMap = new TreeMap<Float,List<String>>();
for (int i=0; i<strings.size(); i++) {
Float key = -scores.get(i);
if (treeMap.get(key)==null)
treeMap.put(key, new LinkedList<String>());
treeMap.get(key).add(strings.get(i));
}
List<String> sortedStrings = new ArrayList<String>(strings.size());
for (List<String> set: treeMap.values()) {
sortedStrings.addAll(set);
}
return sortedStrings;
}
结果是:
sorting 10000 took 29 ms.
sorting 30000 took 16 ms.
sorting 100000 took 25 ms.
sorting 300000 took 229 ms.
sorting 1000000 took 374 ms.
sorting 3000000 took 2723 ms.