Java 中非拉丁字母表的排序列表

Sorting List with non Latin alphabet in Java

我需要按键对 LinkedHashMap 进行排序,这是我通过转换为列表并使用 Collections.sort 实现的。但它只适用于英文字母表,现在我需要对俄语字母表进行同样的操作,但它不再适用了。

请看下面我的代码。我试过添加 Collator collator = Collator.getInstance(new Locale("ru", "RU")); 但它没有帮助...

    private static void sortKeys(Map<String, Integer> map) {
        Set<Map.Entry<String, Integer>> wordSet = map.entrySet();

        List<Map.Entry<String, Integer>> wordEntryList = new ArrayList<Map.Entry<String, Integer>>(wordSet);

        Collections.sort(wordEntryList, new Comparator<Map.Entry<String, Integer>>() {
            @Override
            public int compare(Map.Entry<String, Integer> o1, Map.Entry<String, Integer> o2) {
                Collator collator = Collator.getInstance(new Locale("ru", "RU"));
                return collator.compare(o1.getKey(), o2.getKey());
            }
        });

        map.clear();

        for (Map.Entry<String, Integer> m : wordEntryList) {
            map.put(m.getKey(), m.getValue());
        }
    }

Key是俄语单词,value是数字,需要按键排序。请看下面的例子。

预计:

  1. 前 - 18
  2. пушкин - 18
  3. 第 15 期
  4. тигруля - 15
  5. игрив - 12
  6. котенок - 12
  7. красив - 11
  8. манул - 11

实际:

  1. пушкин - 18
  2. 前 - 18
  3. тигруля - 15
  4. 第 15 期
  5. котенок - 12
  6. игрив - 12
  7. манул - 11
  8. красив - 11

单词是地图中的键,数字是值。号码单独排序,排序没有play。

实际上你的代码工作正常

Map<String, Integer> map = new LinkedHashMap<>();
map.put("ггг", 4);
map.put("ввв", 3);
map.put("ааа", 1);
map.put("ббб", 2);
sortKeys(map);
System.out.println(map);

打印

{ааа=1, ббб=2, ввв=3, ггг=4}

可能的问题 - 您尝试使用 HashMap 而不是 LinkedHashMap。 HashMap 无法保持顺序,但 LinkedHashMap 可以。

还有一件事。 Collections.sort() 接受比较列表。
您试图使用 Map.Entry 作为列表的元素。
Entry 不扩展 Comparable,这就是为什么你不能简单地写

Collections.sort(wordEntryList); // compile error

最后的补充。如果你想摆脱 Collat​​or,你可以这样写

private static void sortLinkedMap(LinkedHashMap<String, Integer> map) {
    ArrayList<String> keysList = new ArrayList<>(map.keySet());
    Collections.sort(keysList); // works fine with keys(String) as elements
    HashMap<String, Integer> tempMap = new HashMap<>(map);
    map.clear();
    for (String key : keysList) {
        map.put(key, tempMap.get(key));
    }
}

我会尝试使用 Java API 和 return 新地图来简化排序:

var sorted = new TreeMap(Collator.getInstance(new Locale("ru", "RU")));
sorted.putAll(map);
return sorted;

这是通过委托给按键排序的 TreeMap 来实现的。 排序方式由Comparator(即Collat​​or)决定。

tl;博士

使用 NavigableMap/SortedMap 而不是编写所有代码。

new TreeMap <>(                   // `TreeMap` implements `NavigableMap`, keeping keys in sorted order.
    Collator.getInstance(         // `Collator` implements `Comparator`, needed to define the way in which to compare our keys of Russian text.
        new Locale.Builder()
        .setLanguage( "ru" )
        .setScript( "Cyrl" )
        .build() 
    ) 
)                                 // Returns an empty `TreeMap`. 
.putAll(                          // Copies the mappings from other map to this map.
        Map.of(                   // Convenient literals syntax to produce an unmodifiable `Map`. 
                "игрив" , 12 ,
                "котенок" , 12 ,
                "пушкин" , 18 ,
                "тигруля" , 15 ,
                "красив" , 11 ,
                "наше" , 18 ,
                "манул" , 11 ,
                "полете" , 15
        )                          // Returns an unmodifiable `Map`. 
)                            

并调用 toString 生成 NavigableMap 的文本表示。

{игрив=12, котенок=12, красив=11, манул=11, наше=18, полете=15, пушкин=18, тигруля=15}

详情

警告:我对俄语和西里尔字母一无所知。

NavigableMap

你太辛苦了。如果您想要一个键保持排序的映射,请使用 NavigableMap (or its predecessor SortedMap).

的实现

TreeMap class 就是这样一种实现方式。

NavigableMap< String , Integer > map = new TreeMap<>( myLinkedHashMap ) ;

既然你想对字符串进行排序,你应该告诉 TreeMap 使用自定义的 Comparator, a specific Collator. In your case, you want the Russian language using the Cyrillic script

Locale locale = new Locale.Builder().setLanguage( "ru" ).setScript( "Cyrl" ).build();
Comparator comparator = Collator.getInstance( locale );  // `Collator` class implements `Comparator` interface.
NavigableSet < String > sorted = new TreeSet <>( comparator );

将现有 LinkedHashMap 的内容添加到此 NavigableMap。调用 Map#putAll 复制映射。

sorted.putAll( myLinkedHashMap ) ;

随着条目被添加到这个新的可导航地图中,使用 Comparator/Collator 来比较俄语文本的字符串,键按排序顺序进行维护。

让我们尝试使用使用 Map.of 创建的地图来实现方便的文字语法。

这是完整的示例代码。

Locale locale = new Locale.Builder().setLanguage( "ru" ).setScript( "Cyrl" ).build();
Comparator comparator = Collator.getInstance( locale );  // `Collator` class implements `Comparator` interface.
NavigableMap < String, Integer > map = new TreeMap <>( comparator );

map.putAll(
        Map.of(
                "игрив" , 12 ,
                "котенок" , 12 ,
                "пушкин" , 18 ,
                "тигруля" , 15 ,
                "красив" , 11 ,
                "наше" , 18 ,
                "манул" , 11 ,
                "полете" , 15
        )
);

System.out.println( "map = " + map );

在 macOS 上 运行 in Java 16 时,我得到以下信息。在 Java 12 run live at IdeOne.com.

中查看相同的代码和相同的结果

map = {игрив=12, котенок=12, красив=11, манул=11, наше=18, полете=15, пушкин=18, тигруля=15}


经过多次实验,我无法得到您预期或实际的结果。虽然我不懂俄语或西里尔文,但我必须问:

  • 您确定您的预期结果是正确的吗?
  • 你是如何得到实际结果的?

speculates that you want to sort on two levels, first by the value, and then by the key. If so, you really should have stated this in the Question. I'll not address the issue here. But for reference, see .