【问题标题】:Why is uppercase not sorted correctly here?为什么这里的大写字母排序不正确?
【发布时间】:2014-08-18 18:26:13
【问题描述】:

我正在尝试对 List<String> 的项目进行排序。这是未排序的List,以及它当前的排序方式:

Unsorted: [Pineapple, pineapple, apple, apricot, Banana, mango, Mango, melon, peach]
Sorted: [apple, apricot, Banana, mango, Mango, melon, peach, Pineapple, pineapple]

Mango怎么没有放在mango前面,为什么Pineapple放在pineapple前面?

这是我的代码:

import java.util.*;
import java.lang.*;
import java.io.*;

class Test {
    public static void main (String[] args) throws java.lang.Exception {
        List<String> fruits = new ArrayList<String>(7);

        fruits.add("Pineapple");
        fruits.add("pineapple");
        fruits.add("apple");
        fruits.add("apricot");
        fruits.add("Banana");
        fruits.add("mango");
        fruits.add("Mango");
        fruits.add("melon");        
        fruits.add("peach");

        System.out.println("Unsorted: " + fruits);

        Collections.sort(fruits, new Comparator<String>() {
            @Override
            public int compare(String o1, String o2) {              
                return o1.compareToIgnoreCase(o2);
            }
        });

        System.out.println("Sorted: " + fruits);
    }
}

【问题讨论】:

  • 因为您使用的是忽略大小写的比较。
  • 我已回滚到修订版 1,因为修订版 2 将意外输出显示为所需的结果。
  • @admdrew:请您停止以明显改变其含义的方式编辑问题(并使已经令人困惑的情况变得更糟)。
  • @NPE 抱歉,我最初的编辑确实是错误的。我更改了措辞以反映实际输出与预期输出。

标签: java sorting alphabetical


【解决方案1】:

您使用compareToIgnoreCase() 作为比较方法,因此它将'Pineapple' 和'pineapple' 比较为0(相同的字符串),使它们按照排序时的顺序排列,因为Collections.sort 保证相同的元素获胜'不被重新排序。 换句话说,'Pineapple' 出现在 'pineapple' 之前,所以现在由于 ignoreCase,它们是相等的字符串,'Pineapple' 将保持在 'pineapple' 的前面。

由于未排序列表在“菠萝”之前有“菠萝”,因此比较会将它们以相同的顺序放入排序列表中。这些相同的规则适用于“芒果”和“芒果”。您正在寻找的比较方法只是compareTo(),它确实考虑了大写和小写字母。

【讨论】:

  • 我对OP的要求的理解是预期的结果是apple, apricot, Banana, Mango, mango, melon, peach, Pineapple, pineapple。这不会那样做,所以要么这个答案是错误的,要么我对这个问题的解释是错误的。
  • 你确定吗?据我了解,我们知道未排序列表是什么。然后使用 Collections.sort 方法对列表进行排序,但是通过忽略大小写来覆盖比较函数以进行排序。最重要的是。 Collections.sort 是稳定的,因此保证不会重新排序相等的元素。因此,预期结果是不可能的,因为比较函数重载将 'Mango' 和 'mango' 更改为被视为相同的元素,因此它们保持与未排序列表相同的顺序。
  • 是否有可能(当然是顺便说一句)不应该影响对问题的解释。 ;-)
【解决方案2】:

为什么'Mango'没有放在'mango'之前,为什么'Pineapple'放在'pineapple'之前?

根据您的比较器,“Mango”和“mango”比较相等。因为Collections.sort()stable,所以比较相等的项会按照它们在原始集合中的顺序返回(不稳定 排序会以任意顺序返回它们)。

如果您希望“Mango”总是在“mango”之前返回,那么您的比较器需要反映这一点。这意味着“Mango”需要比较小于“mango”(但大于“apple”、“apricot”、“Banana”等)。

实现此目的的一种方法是使用以下比较器:

Collections.sort(fruits, new Comparator<String>() {
    @Override
    public int compare(String o1, String o2) {              
        int ret = o1.compareToIgnoreCase(o2);
        if (ret == 0) {
            ret = o1.compareTo(o2);
        }
        return ret;
    }
});

这将返回:

Sorted: [apple, apricot, Banana, Mango, mango, melon, peach, Pineapple, pineapple]

【讨论】:

    【解决方案3】:

    因为您使用的是compareToIgnoreCase,顾名思义,在比较两个字符串时忽略大小写。所以,mango 和 Mango 是相同的,并且以与它们相同的顺序被排除(排序是 stable,例如:equals 元素按照它们在排序之前的顺序离开。)。

    附带说明,您的比较器与String.CASE_INSENSITIVE_ORDER 相同。 compareToIgnoreCase 只需调用该比较器。

    【讨论】:

      【解决方案4】:

      According to the javadocs Collections.sort 保证稳定 - 比较相等的项目的相对顺序不会因排序而改变。如果您想强制执行将大写字母放在小写字母之前的排序,那么您需要使用实现该排序的不同比较器,实现该排序的最简单方法可能是使用java.text.RuleBasedCollator

      【讨论】:

        【解决方案5】:

        你做的一切都是正确的。

        “mango”确实应该出现在“pineapple”之前和“apple”之后。

        但是“菠萝”和“菠萝”是“相同的”。平等的。 “0”。因为你说的是​​“ignoreCase”。

        【讨论】:

        • 这没有回答 OP 的问题。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2020-08-24
        • 2013-06-25
        • 2012-10-11
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多