我该如何按字母顺序对列表进行排序?

224

我有一个包含国家名称的 List<String> 对象,如何按字母顺序对此列表进行排序?

16个回答

253

假设这些都是字符串,使用方便的静态方法sort

Collections.sort(listOfCountryNames)

如果您有像“UK”这样的国家名称,那么就会出现错误。 - Tom Hawtin - tackline
1
在这种情况下,您可以将Comparator作为额外参数传递。实现该比较器将是有趣的部分。 - Thilo
7
实现Comparator = 使用java.text.Collator.getInstance。 - Thilo
4
这个回答并没有回答问题,因为与字母顺序排序不同的是,'Z''a' 之前。这个问题是关于字母顺序排序的。 - Chai T. Rex

158

使用Collections.sort的解决方案

如果你被迫使用了那个List,或者你的程序结构如下:

  • 创建List
  • 添加一些国家名称
  • 排序一次
  • 从此以后不再修改该列表

那么Thilo的答案将是最好的方法。如果你结合Tom Hawtin-tackline的建议,你会得到:

java.util.Collections.sort(listOfCountryNames, Collator.getInstance());

使用TreeSet的解决方案

如果你可以自由决定,并且你的应用程序可能会变得更加复杂,那么你可以改变你的代码,使用TreeSet代替。这种类型的集合在插入条目时会自动排序,无需调用sort()方法。

Collection<String> countryNames = 
    new TreeSet<String>(Collator.getInstance());
countryNames.add("UK");
countryNames.add("Germany");
countryNames.add("Australia");
// Tada... sorted.

关于为什么我更喜欢使用TreeSet的一些注解

这有一些微妙但重要的优点:

  • 它简单。虽然只比其他方式短一行。
  • 无论你做什么,都不用担心“这个列表现在是否真的被排序了”,因为TreeSet始终是有序的。
  • 您不能有重复的条目。根据您的情况,这可能是一个利也可能是一个弊。如果你需要重复项,那就使用List。
  • 经验丰富的程序员看到TreeSet<String> countyNames时立即知道:这是一个没有重复项的排序字符串集合,并且我可以确信它在每一刻都是正确的。这么短的声明中包含了如此多的信息。
  • 在某些情况下具有真正的性能优势。如果您使用List,并经常插入值,并且在这些插入之间可以读取列表,则必须在每次插入之后对列表进行排序。集合也是如此,但速度要快得多。

为正确的任务选择正确的集合是编写简短且无漏洞代码的关键。在这种情况下,它可能不太明显,因为您只能节省一行。但我已经停止了统计有多少次看到某人想确保没有重复项时使用List,然后自己构建该功能。或者更糟糕的是,当您真正需要Map时却使用两个List。

不要误解:使用Collections.sort并没有错误或缺陷。但在许多情况下,TreeSet更加简洁。


1
TreeSet避免了意外的重复(这可能是好事或坏事),而且它应该会更快(尽管在输入大小方面不会有太大差别),并且它总是会排序,而不是在所有输入之后进行排序(除非你在每次插入后都对列表进行排序),这可能很重要,但也可能不重要。因此更快。 - TofuBeer
1
@TofuBeer 我只是在你也在做的时候澄清这个问题。如果你真的关心什么更快,可以看一下 https://dev59.com/b3VC5IYBdhLWcg3w1E7w - Lena Schimmel
9
如果集合中的项是可变的,TreeSet 将无法保持排序。 - Joshua Goldberg
3
@JoshuaGoldberg,我认为它不仅会变得没有排序,而且也会停止正常工作。如果对象的变异影响其排序顺序,至少是这样。树集依赖于项目被排序以执行其任务(如搜索、删除、插入等)。 - Lena Schimmel
1
这并没有回答问题,因为String默认使用的排序方式是字典排序,而不是按字母顺序排序。 'Z'在字典排序中排在'a'之前,与按字母顺序排序不同。 - Chai T. Rex
显示剩余4条评论

38

你可以使用Java 8 Stream或Guava创建一个新的排序副本:

// Java 8 version
List<String> sortedNames = names.stream().sorted().collect(Collectors.toList());
// Guava version
List<String> sortedNames = Ordering.natural().sortedCopy(names); 

另一个选项是通过Collections API原地进行排序:

Collections.sort(names);

1
第一个示例并没有回答问题,因为用于String的默认排序是词典排序,而不是字母表顺序。 'Z'在字母表排序中排在'a'之前。 - Chai T. Rex

28

迟做总比不做好!以下是我们可以这样做的方式(仅供学习目的)-

import java.util.List;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;

class SoftDrink {
    String name;
    String color;
    int volume; 

    SoftDrink (String name, String color, int volume) {
        this.name = name;
        this.color = color;
        this.volume = volume;
    }
}

public class ListItemComparision {
    public static void main (String...arg) {
        List<SoftDrink> softDrinkList = new ArrayList<SoftDrink>() ;
        softDrinkList .add(new SoftDrink("Faygo", "ColorOne", 4));
        softDrinkList .add(new SoftDrink("Fanta",  "ColorTwo", 3));
        softDrinkList .add(new SoftDrink("Frooti", "ColorThree", 2));       
        softDrinkList .add(new SoftDrink("Freshie", "ColorFour", 1));

        Collections.sort(softDrinkList, new Comparator() {
            @Override
            public int compare(Object softDrinkOne, Object softDrinkTwo) {
                //use instanceof to verify the references are indeed of the type in question
                return ((SoftDrink)softDrinkOne).name
                        .compareTo(((SoftDrink)softDrinkTwo).name);
            }
        }); 
        for (SoftDrink sd : softDrinkList) {
            System.out.println(sd.name + " - " + sd.color + " - " + sd.volume);
        }
        Collections.sort(softDrinkList, new Comparator() {
            @Override
            public int compare(Object softDrinkOne, Object softDrinkTwo) {
                //comparision for primitive int uses compareTo of the wrapper Integer
                return(new Integer(((SoftDrink)softDrinkOne).volume))
                        .compareTo(((SoftDrink)softDrinkTwo).volume);
            }
        });

        for (SoftDrink sd : softDrinkList) {
            System.out.println(sd.volume + " - " + sd.color + " - " + sd.name);
        }   
    }
}

5
不需要这么多代码,一行就够了。看看Lena的回答就知道了。 - james.garriss
1
这可能是一个练习,但如果我在生产代码中看到它,我会立即砍掉它。 - katzenhut
2
@james.garriss,Lena的回答是针对简单的字符串列表的,而这个问题是针对包含要排序的字符串属性的对象列表的。 - Muneeb Mirza
1
是的,当在生产环境中使用对象时,这个答案非常有帮助。字符串列表并不常见。 - JustRandom
这个并不是回答问题的,因为用于 String 的默认排序是字典排序,而不是按字母顺序排序。 'Z' 在字典排序中位于 'a' 之前,与按字母顺序排序不同。 - Chai T. Rex

21

使用 Java 8,一行代码实现:

list.sort(Comparator.naturalOrder());

1
这并不回答问题,因为使用String的自然顺序Comparator并非按字母顺序排序。 'Z'排在'a'之前,而不是按字母顺序排序。 - Chai T. Rex

15

除非你只排序没有口音的英文字符串,否则你可能想使用Collator。它可以正确地排序带有变音符号的字符,可以忽略大小写和其他语言特定的东西:

Collections.sort(countries, Collator.getInstance(new Locale(languageCode)));
你可以设置Collator的强度,请参见javadoc。
以下是斯洛伐克文的示例,其中Š应该放在S之后,但在UTF中ŠZ之后:
List<String> countries = Arrays.asList("Slovensko", "Švédsko", "Turecko");

Collections.sort(countries);
System.out.println(countries); // outputs [Slovensko, Turecko, Švédsko]

Collections.sort(countries, Collator.getInstance(new Locale("sk")));
System.out.println(countries); // outputs [Slovensko, Švédsko, Turecko]

11
使用带有两个参数的Collections.sort方法。您将需要一个适当的Comparator,该比较器会适当地处理大小写(即进行词法排序,而不是基于UTF16的排序),例如通过java.text.Collator.getInstance获取的比较器。

10

这就是您要找的内容。

listOfCountryNames.sort(String::compareToIgnoreCase)

2
不支持带有É è等字符的语言...您需要在操作之前去掉重音。 - Vincent D.

7
更简单的方法是使用方法引用。
 list.sort(String::compareTo);

5
您可以使用以下代码行。
Collections.sort(listOfCountryNames, String.CASE_INSENSITIVE_ORDER)

这类似于Thilo的建议,但不会区分大小写字符。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接