Java - 如何根据首字母对地图值进行排序?
Java - How to sort a map values according to their first letter?
我有一个 Java 地图,我使用此代码对其字符串值按字母顺序排序:
public <K, V> LinkedHashMap<K, V> sortMapByValues( 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 ) {
// Sort this word alphabetically in the map :
String a = (String)e1.getValue();
String b = (String)e2.getValue();
int diff = a.compareToIgnoreCase( b );
if (diff == 0)
diff = a.compareTo(b);
return diff != 0 ? diff : 1; // Fix words having the same spelling.
}
}
);
sortedEntries.addAll( map.entrySet() );
LinkedHashMap<K, V> sortedMap = new LinkedHashMap<K, V>();
for( Map.Entry<K, V> sortedEntry: sortedEntries )
sortedMap.put( sortedEntry.getKey(), sortedEntry.getValue() );
return sortedMap;
}
由于地图有数千个值,上面的代码运行速度足够快,可以快速给出我想要的结果。现在我需要更改此代码并更新它以根据另一个条件对地图值进行排序,而不是按字母顺序排序。
我有一个变体 ArrayList 的字母,如:
ArrayList lettersArrayList = new ArrayList<String>( Arrays.asList( "E", "C", "A", "Z", "Q", "R", "B", "L", "D", ... ) );
此 ArrayList 中的字母值由用户指定,因此它们可能具有任何其他字母值和顺序。 我需要根据这个ArrayList对Map的String值进行排序,所以"E"开头的词在前,然后是"C"开头的词,以此类推。这可能吗?
首先,你的比较器不正确:
return diff != 0 ? diff : 1;
如果a
和b
拼写相同,比较a
和b
得到1,意思是a > b
,比较b
到a
也给出1,意思是b > a
。你可以使用
return diff != 0 ? diff : Integer.compare(System.identityHashCode(e1), System.identityHashCode(e2));
(几乎)正确。如果您使用大量内存并且两个单独的对象碰巧以相同的系统哈希码结尾,这仍然可以使两个条目实际上不同但它们相等,这是非常非常不可能的。
现在,要回答您的问题,您只需比较两个条目的首字母索引即可:
String a = (String)e1.getValue();
String b = (String)e2.getValue();
int index1 = list.indexOf(a.substring(0, 1));
int index2 = list.indexOf(b.substring(0, 1));
int diff = Integer.compare(index1, index2);
这可行,但效率极低,因为
- indexOf() 是 O(n)
- 你最好使用 Character 而不是 String 来存储单个字符。
因此,您应该使用 HashMap<Character, Integer>
而不是 List<String>
来存储字母,其中每个字母都与其位置相关联。在此映射中查找将是 O(1),使比较器更快。
我有一个 Java 地图,我使用此代码对其字符串值按字母顺序排序:
public <K, V> LinkedHashMap<K, V> sortMapByValues( 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 ) {
// Sort this word alphabetically in the map :
String a = (String)e1.getValue();
String b = (String)e2.getValue();
int diff = a.compareToIgnoreCase( b );
if (diff == 0)
diff = a.compareTo(b);
return diff != 0 ? diff : 1; // Fix words having the same spelling.
}
}
);
sortedEntries.addAll( map.entrySet() );
LinkedHashMap<K, V> sortedMap = new LinkedHashMap<K, V>();
for( Map.Entry<K, V> sortedEntry: sortedEntries )
sortedMap.put( sortedEntry.getKey(), sortedEntry.getValue() );
return sortedMap;
}
由于地图有数千个值,上面的代码运行速度足够快,可以快速给出我想要的结果。现在我需要更改此代码并更新它以根据另一个条件对地图值进行排序,而不是按字母顺序排序。
我有一个变体 ArrayList 的字母,如:
ArrayList lettersArrayList = new ArrayList<String>( Arrays.asList( "E", "C", "A", "Z", "Q", "R", "B", "L", "D", ... ) );
此 ArrayList 中的字母值由用户指定,因此它们可能具有任何其他字母值和顺序。 我需要根据这个ArrayList对Map的String值进行排序,所以"E"开头的词在前,然后是"C"开头的词,以此类推。这可能吗?
首先,你的比较器不正确:
return diff != 0 ? diff : 1;
如果a
和b
拼写相同,比较a
和b
得到1,意思是a > b
,比较b
到a
也给出1,意思是b > a
。你可以使用
return diff != 0 ? diff : Integer.compare(System.identityHashCode(e1), System.identityHashCode(e2));
(几乎)正确。如果您使用大量内存并且两个单独的对象碰巧以相同的系统哈希码结尾,这仍然可以使两个条目实际上不同但它们相等,这是非常非常不可能的。
现在,要回答您的问题,您只需比较两个条目的首字母索引即可:
String a = (String)e1.getValue();
String b = (String)e2.getValue();
int index1 = list.indexOf(a.substring(0, 1));
int index2 = list.indexOf(b.substring(0, 1));
int diff = Integer.compare(index1, index2);
这可行,但效率极低,因为
- indexOf() 是 O(n)
- 你最好使用 Character 而不是 String 来存储单个字符。
因此,您应该使用 HashMap<Character, Integer>
而不是 List<String>
来存储字母,其中每个字母都与其位置相关联。在此映射中查找将是 O(1),使比较器更快。