How do I sort an ArrayList lexicographically?
Asked Answered
D

6

8

I am trying to sort an ArrayList of Strings that represent card values. So, some cards contain letters ("King") and some contain Strings containing only a number ("7"). I know to use Collections.sort, but it only sorts Strings that contain letters. How do I get the ArrayList to be sorted by number as well as alphabetically?

Edit: Sorry, I must not have been paying much attention when I looked at the sorting. The sort works correctly, I must have just been thrown off by the fact that a 10 will come before a 2. Thanks

Derisible answered 8/6, 2010 at 16:9 Comment(2)
"I know to use Collections.sort, but it only sorts Strings that contain letters" uh?Drucilla
Not sure what you are trying to do, sorting the collection will sort everything (including "7") alphabetically. Numbers are placed before A, so they would end up on top. If you want 7 to be stored under "s" you would have to create a dictionary with something like the Generic Collections dictionary class, which has the display string "7" as well as the code/text representation "Seven", or something like that.Dotti
U
10

No, Collections.sort will sort everything, using an Unicode ordinal lexicographic comparison as that's the behaviour of String.compareTo. "7" will come before "King", and "10" will come before "2".

Undoing answered 8/6, 2010 at 16:14 Comment(1)
yep - java.sun.com/j2se/1.4.2/docs/api/java/lang/…Drucilla
F
4

As I understand, you have an array like ["7", "Queen", "9", "6"] and you want it to look like ["Queen", "9", "7", "6"] (or in reverse order) after sorting is done.

I'd recommend to make it a bit more object-oriented i.e. create class Card with fields name and value:

class Card {
   private final String name;
   private final int value;
   ...
   //constructor and getters
}

and after that create instances in this manner:

Card six = new Card("6", 6);
Card ten = new Card("10", 10);
Card queen = new Card("Queen", 12);

After that it'll be much easier to make all operations with cards (and sorting particularly) using field value instead of cards' names.

Findley answered 8/6, 2010 at 16:20 Comment(1)
<nitpick> As a convention, cards generally also have "suits". </nitpick>Bricky
C
1

As @Jon Skeet said, the built-in sort will compare based on Unicode values. You'd have to write your own sorting method.

As long as you're writing your own code, though, might I suggest an enumeration? A deck of cards is one of the canonical examples for use of enums. The short version is that you can declare your own sort order for a group of things; you could even make the king of spades outrank the king of diamonds, if you wanted. Check out Sun's tutorial here.

Cheyenne answered 8/6, 2010 at 16:20 Comment(0)
P
0

I know to use Collections.sort, but it only sorts Strings that contain letters. How do I get the ArrayList to be sorted by number as well as alphabetically?

If the string is a number it is already being sorted ( as an String though ) look:

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 );
    }
}

Prints

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

Is that what you need?

edit

Assuming ( guessing ) what you need is to sort a deck of cards, which have both numbers and "letters" ( J, Q, K, A ) you may try to use a custom comparator.

Here's one that takes into consideration the numbers "as numbers" the the rest as strings, so "10" comes after "2" but before "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]

If that's what you need I guess this would help you to figure out the rest. Probably the next thing would be how to sort spades vs. hearts.

Following the answer by Roman you could create a class and implement the Comparable interface:

  class Card implements Comparable<Card> {
       public int compareTo( Card other ) {  
           // add custom logic to compare one card with other 
       }
   }
Polyvinyl answered 8/6, 2010 at 16:14 Comment(2)
It's not what he's asking. I think he wants you to write custom Comparator for all card names.Fungistat
@Nikita: I understand that he "thinks" numbers are not including in the sort. Probably the OP needs some clarification.Polyvinyl
L
0

Sort will sort everything according to your charset. In otherwords, all numbers will come before letters in the lexicographic order. For example, decimal numbers start with a '.' and out of order lexicographically.

If you want to change this, make Comparator object. You could then put the items in whatever order you like.

For example, this will sort numbers in numerical order, and also words in lexical order:

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);

PS not tested!

Longstanding answered 8/6, 2010 at 16:16 Comment(0)
P
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;
    }
}
Pie answered 16/8, 2023 at 8:37 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.