【问题标题】:Sorting List with non Latin alphabet in JavaJava中非拉丁字母的排序列表
【发布时间】:2021-08-22 21:06:51
【问题描述】:

我需要按键对 LinkedHashMap 进行排序,这是通过转换为 List 并使用 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是数字,需要key排序。请看下面的例子。

预期:

  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

单词是 Map 中的键,数字是值。数字是单独排序的,在排序中没有任何作用。

【问题讨论】:

  • 有一个非常相似的问题的解决方案,但它是在 PHP 中。 stackoverflow.com/questions/27187285/…你不妨看看
  • 您的输入和预期输出是什么?这里是说英语的人。
  • 给出简短的示例输入数据,并显示预期结果与实际结果。
  • 您仍然没有显示一致的 MCVE。当我使用此输入 {пушкин=18, тигруля=15, манул=11, котенок=12, красив=11, наше=18, игрив=12, полете=15} 运行您的代码时,我得到以下结果:{игрив=12 , котенок=12, красив=11, манул=11, наше=18, полете=15, пушкин=18, тигруля=15} 与您的“实际”结果不符。在我的任何实验中,我都无法匹配您的预期或实际结果。例如,我总是以наше 结尾,而不是在第一或第二位置。虽然我对俄语或西里尔字母一无所知,但您的代码还有其他问题。
  • @BasilBourque 显然,该地图应该按值降序排序并仅作为次要标准按键升序。但是,问题中没有说明这一点,也没有反映在显示的代码和接受的答案中,这无济于事。

标签: java sorting collections


【解决方案1】:

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(或其前身SortedMap)的实现。

TreeMap 类就是这样一种实现。

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

由于您要对字符串进行排序,您应该告诉TreeMap 使用自定义Comparator,即特定的Collator。在您的情况下,您希望 Russian language 使用 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 上的 Java 16 中运行时,我得到以下信息。在 Java 12 run live at IdeOne.com 中查看相同的代码和相同的结果。

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


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

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

comment by Holger 推测您希望在两个级别上进行排序,首先按值,然后按键。如果是这样,您真的应该在问题中说明这一点。我不会在这里解决这个问题。但供参考,请参阅Using comparator with multiple comparators

【讨论】:

    【解决方案2】:

    实际上你的代码运行良好

    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 作为列表的元素。
    条目不扩展 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));
        }
    }
    

    【讨论】:

    • 您是否尝试过问题中的示例数据?我做到了,但我无法匹配问题中显示的实际或预期结果。
    • 抱歉,我回答时样本数据缺失。实际上排序工作完美。目前这里在作者的预期结果中有错误,它应该像你在上面的评论中写的那样排序en.wikipedia.org/wiki/Russian_alphabet
    【解决方案3】:

    我会尝试使用 Java API 来简化排序并返回新地图:

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

    这通过委托给按键排序的 TreeMap 来工作。 排序方法由 Comparator(即 Collat​​or )决定。

    【讨论】:

      猜你喜欢
      • 2015-02-26
      • 1970-01-01
      • 1970-01-01
      • 2015-03-24
      • 1970-01-01
      • 2013-01-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多