如何按字典顺序对ArrayList进行排序?

8
我正在尝试对代表卡牌值的字符串的ArrayList进行排序。因此,有些卡牌包含字母(“King”),而有些卡牌仅包含数字的字符串(“7”)。我知道要使用Collections.sort,但它只能对包含字母的字符串进行排序。如何使ArrayList按数字和字母顺序排序?
编辑:抱歉,当我查看排序时可能没有注意到。排序是正确的,我可能只是被10在2之前的事实所迷惑了。谢谢

1
我知道如何使用Collections.sort,但它只能对包含字母的字符串进行排序。嗯? - leonbloy
1
不确定您想要做什么,对集合进行排序将按字母顺序对所有内容(包括“7”)进行排序。数字会排在A之前,因此它们会出现在顶部。如果您希望将7存储在“s”下面,您需要创建一个类似于通用集合字典类的字典,其中具有显示字符串“7”以及代码/文本表示“Seven”等内容。 - Cobusve
6个回答

10

不会,Collections.sort 会对所有元素进行排序,使用Unicode字典序比较,因为这就是String.compareTo的行为。"7"会排在"King"之前,"10"会排在"2"之前。


是的 - http://java.sun.com/j2se/1.4.2/docs/api/java/lang/String.html#compareTo(java.lang.String) - leonbloy

4
据我所理解,您有一个数组,如["7", "Queen", "9", "6"],您希望在排序完成后它看起来像["Queen", "9", "7", "6"](或按相反顺序排列)。
我建议将其更改为面向对象的方式,即创建具有名称和值字段的Card类。
class Card {
   private final String name;
   private final int value;
   ...
   //constructor and getters
}

然后,可以通过以下方式创建实例:
Card six = new Card("6", 6);
Card ten = new Card("10", 10);
Card queen = new Card("Queen", 12);

此后,使用字段value而不是卡片名称来进行所有与卡片相关的操作(特别是排序)将变得更加容易。


1
<nitpick> 通常作为一种惯例,纸牌也会有“花色”。 </nitpick> - fmark

1

正如@Jon Skeet所说,内置的sort(排序)将基于Unicode值进行比较。 你需要编写自己的排序方法。

只要你在编写自己的代码,我可以建议一个枚举吗?一副牌是枚举使用的典型示例之一。简而言之,您可以为一组事物声明自己的排序顺序; 如果您想要,您甚至可以使黑桃皇后胜过方块皇后。请查看Sun的教程here


0
我知道如何使用Collections.sort,但它只能对包含字母的字符串进行排序。我该如何让ArrayList按数字和字母顺序排序呢?
如果字符串是一个数字,它已经被排序了(虽然是作为字符串)。看这里:
import java.util.*;
class Sort {
    public static void main( String [] args  ) {
        List list = Arrays.asList("Kings","7", "Abcd", "3.1416");
        Collections.sort( list );
        System.out.println( list );
    }
}

打印

$ java Sort
[3.1416, 7, Abcd, Kings]

这是你需要的吗?

编辑

假设(猜测)你需要对一副牌进行排序,其中既有数字又有“字母”(J、Q、K、A),你可以尝试使用自定义比较器。

这里有一个考虑将数字“作为数字”和其余部分作为字符串的比较器,因此“10”在“2”之后但在“Kings”之前。

import java.util.*;
class Sort {
    public static void main( String [] args  ) {

        List<String> list = Arrays.asList("Kings","7", "Queen", "3", "10", "A", "2", "8", "Joker");
        Collections.sort( list , new Comparator<String>(){
            public int compare( String a, String b ){
                // if both are numbers
                if( a.matches("\\d+") && b.matches("\\d+")) {
                    return new Integer( a ) - new Integer( b );
                }
                // else, compare normally. 
                return a.compareTo( b );
            }
        });
        System.out.println( list );
    }
}

$ java Sort
[2, 3, 7, 8, 10, A, Joker, Kings, Queen]

如果这是你需要的,我猜这会帮助你弄清剩下的事情。可能接下来需要解决的问题是如何对黑桃和红心进行排序。
按照Roman的答案,你可以创建一个类并实现Comparable接口:
  class Card implements Comparable<Card> {
       public int compareTo( Card other ) {  
           // add custom logic to compare one card with other 
       }
   }

这不是他要求的。我认为他希望您为所有卡牌名称编写自定义比较器。 - Nikita Rybak
@Nikita:我理解他“认为”数字不包括在排序中。可能OP需要一些澄清。 - OscarRyz

0

Sort将根据您的字符集对所有内容进行排序。换句话说,在字典顺序中,所有数字都将排在字母之前。例如,十进制数以“.”开头,并且在字典顺序上是无序的。

如果您想更改此设置,请创建Comparator对象。然后,您可以按任何顺序放置项目。

例如,这将按数字顺序和词汇顺序对单词进行排序:

class CardComparator extends Object implements Comparator{
 public int compare(Object a, Object b){
  try{
   double d1=Double.valueOf(a.toString());
   try{
     double d2=Double.valueOf(b.toString());
     return (d2>d1)?1:-1;            // both numeric
   }catch(NumberFormatException e){ // a is numeric but b isn't
     return 1;
   }
  }catch(NumberFormatException e){  
    try{
     double d2=Double.valueOf(b.toString()); 
     return -1;                       // a is nonnumeric but b is
    }catch(NumberFormatException e){  // both nonnumeric
      return a.toString().compareTo(b.toString);
    }
  }
 }
}
Comparator comparator=new CardComparator();
Collections.sort(cards, comparator);

注意:未经测试!


0
Sharing an example where I have created two comparator for Lexicographical order, one for Integers and other for String
Note: String by default support Lexicographical order 

import java.util.*;

public class ArrayListLexicographicalSort {

    public static void main(String[] args) {

        //Comparator for Lexicographical order for Integer
        Comparator<Integer> comparator = (i,j)->ArrayListLexicographicalSort.lexicographicalSort(i,j);
        //Comparator for Lexicographical order for String
        Comparator<String> stringComparator = (i,j)->i.compareTo(j);

        //list of integers
       List<Integer> integerList = Arrays.asList(101,11,2,100,10);
        System.out.println(integerList);
        //o/p->[101, 11, 2, 100, 10]
        //creating a treeset with Lexicographical sort order for Integer
        TreeSet<Integer> integerTreeSet = new TreeSet<>(comparator);
        integerTreeSet.addAll(integerList);
        //resultant Lexicographical order for integers
        System.out.println(integerTreeSet);
        //o/p->[10, 100, 101, 11, 2]

        //list of Strings
        List<String> stringList = Arrays.asList("Abhinav","Kumar","Aabhinav","101","100","2");
        System.out.println(stringList);
        //o/p->[Abhinav, Kumar, Aabhinav, 101, 100, 2]
        //creating a treeset with Lexicographical sort order for String
        TreeSet<String> stringTreeSet = new TreeSet<>(stringComparator);
        stringTreeSet.addAll(stringList);
        //resultant Lexicographical order for strings
        System.out.println(stringTreeSet);
        //o/p->[100, 101, 2, Aabhinav, Abhinav, Kumar]
    }

   // method to compare two integer lexicographically
    private static int lexicographicalSort(long input1, long input2){

        // -ve means input1 is smaller
        //  +ve means input1 is larger
        //  0 means input1 and input2 are same
        long inp1 = input1;
        long inp2 = input2;
        int input1Length = 1;
        int input2Length = 1;

        while(inp1/10>0){
            input1Length++;
            inp1 = inp1/10;
        }

        while(inp2/10>0){
            input2Length++;
            inp2 = inp2/10;
        }

        int[] inArr1 = new int[input1Length];
        int[] inArr2 = new int[input2Length];

        inp1 = input1;
        inp2 = input2;

        int min = Math.min(input1Length,input2Length);

        while(inp1/10>0){
            inArr1[--input1Length] = (int)inp1%10;
            inp1 = inp1/10;
        }
        inArr1[--input1Length] = (int)inp1;

        while(inp2/10>0){
            inArr2[--input2Length] = (int)inp2%10;
            inp2 = inp2/10;
        }
        inArr2[--input2Length] = (int)inp2;

        int k = 0;

        while(k<min){
            if( inArr1[k] != inArr2[k]){
                return inArr1[k]-inArr2[k];
            }
            k++;
        }

        return inArr1.length-inArr2.length;
    }
}

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