实现Java比较器以使用自定义排序对集合进行排序的最佳方式(在时间和空间效率方面)是什么。例如 - 我想使用以下顺序对数组进行排序 -
RWQOJMVAHBSGZXNTCIEKUPDYFL
我有以下Java代码,它按预期工作,但不确定是否有任何其他有效的方法来执行相同的操作。
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.lang.Math;
public class DiffSort {
private static String order = "RWQOJMVAHBSGZXNTCIEKUPDYFL";
// sort with comparator
public static Comparator<String> diffNaturalOrder = new Comparator<String>() {
public int compare(String v, String w) {
int diff = 0, iter = 0;
Integer index1, index2;
Integer len1 = v.length();
Integer len2 = w.length();
int len = Math.min(len1, len2); // lesser of 2 strings
for(int i=0; i<len; i++) {
index1 = order.indexOf(v.charAt(i));
index2 = order.indexOf(w.charAt(i));
// if both chars are absent in order string, use natural ordering
if(index1 == -1 && index2 == -1)
diff = new Character(v.charAt(i)).compareTo(new Character(w.charAt(i)));
else if(index1 == -1 && index2 > 0)
diff = 1;
else if(index1 > 0 && index2 == -1)
diff = -1;
else
diff = index1.compareTo(index2);
// break if we found mismatch
if(diff != 0) break;
}
// return smaller string first in sort
if(diff == 0)
diff = len1.compareTo(len2);
return diff;
}
};
// test client
public static void main(String[] args) {
List<String> list = new ArrayList<String>();
list.add("ABCE1!4");
list.add("ABCE1!7");
list.add("!SDF");
list.add("TRWESF!");
Collections.sort(list, DiffSort.diffNaturalOrder);
// print sorted array
for(String s:list)
System.out.println(s);
}
}
/ * OUTPUT * /
ABCE1!4
ABCE1!7
TRWESF!
!SDF
答案 0 :(得分:5)
将order
的所有字符放入Map<Character, Integer>
(整数对应于order
中字符的位置),然后放入for
- 循环中order.indexOf(c)
使用map.get(c)
。
您可以非常轻松地设置此地图:
private static final Map<Character, Integer> map =
new HashMap<Character, Integer>(order.length());
static {
for (int i = 0; i < order.length(); i++)
map.put(order.charAt(i), i);
}
答案 1 :(得分:2)
我还要做的是缓存char的位置计算。
首先,w会在检查地图之前比较字符相等。
然后在map中会存储char的每个组合。
(左,右)
如果离开更早,则返回1 如果权利较早,则返回-1 如果左边的eq右边返回0.
或者你可以创建一个char数组,并在char的位置存储顺序。
public final class CustomAlphabetComparator implements Comparator<String> {
private char order[] = new char[1<<16];
public CustomAlphabetComparator (String alphabet) {
if (alphabet == null) throw new IllegalArgumentException("Input must not be null");
char index = 0;
for(char c : alphabet.toCharArray()) {
order[c] = index++;
}
}
@Override
public int compare(String o1, String o2) {
if(o1 == o2) return 0; //We check the references
if(o1 == null && o2 == null) return 0;
if(o1 != null && o2 == null) return 1;
if(o1 == null && o2 != null) return -1;
if(o1.equals(o2)) return 0; //We check that are equal
char[] c1 = o1.toCharArray();
char[] c2 = o2.toCharArray();
int shortest = c1.length < c2.length ? c1.length : c2.length;
int result = 0;
for(int i = 0; result == 0 & i < shortest; i++ ) {
result = order[c1[i]] - order[c2[i]];
}
return result;
}
}
答案 2 :(得分:0)
显然你所使用的代码是有效的,但有一点需要注意的是String.indexOf(ch)逐个字符地逐字符串,直到找到它正在查找的字符串。如果您的字符串接近“字母表”的末尾,则会产生大量不必要的循环。
我将排序存储在HashMap<Character, Integer>
中,并在恒定时间内从中提取索引信息。应该比循环整个String更快(对于你要比较的每个角色!)......
答案 3 :(得分:0)
这是一个只有大写英文字母的有效比较器(可以扩展,但不是没有限制):
public static Comparator<String> diffNaturalOrder = new Comparator<String>() {
private int[] order = new int[] {7, 9, 16, 22, 18, 24, 11, 8, 17, 4, 19, 25, 5, 14, 3, 21, 2, 0, 10, 15, 20, 6, 1, 13, 23, 12};
public int compare(String v, String w) {
int diff = 0;
int len = Math.min(v.length(), w.length()); // lesser of 2 strings
int o1, o2;
for(int i=0; i<len; i++) {
o1 = order[v.charAt(i)-65];
o2 = order[w.charAt(i)-65];
diff = o1 - o2;
// break if we found mismatch
if(diff != 0) break;
}
if (diff == 0) {
diff = v.length() - w.length();
}
return diff;
}
};
而不是indexOf
或Map<Character, Integer>
,它使用char的整数值(小于65)来索引包含排序数据的数组。可以这样生成数组:
private static void generateArray() {
String order = "RWQOJMVAHBSGZXNTCIEKUPDYFL";
int[] chars = new int[26];
int i = 0;
for (char c : order.toCharArray()) {
chars[c-65] = i++;
}
System.out.println(Arrays.toString(chars));
}