Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to sort a string list consists of digits and alphabets in Java?

I have a list of items consists of digits and alphabets like below:

Original List:

Apple 1
Apple 1
Apple 4
Apple 1A
Apple 1B
Apple 1D
Apple 2A
Apple 2A
Apple 1C
Apple 1B
Apple 2C
Apple 10
Apple 11
Apple 5
Apple 11
Apple 8D
Banana 1
Banana 4
Banana 9D
Banana 9E
Banana 9C
Banana 13
Banana 16

It's a search result from a API but only sorted by alphabetical order of Apples and Bananas. Now I'd like to sort it by the digits (digits randomly come with letters A, B, C, D, E) like below:

The digits with A, B, C, D, E letters should be sorted by both digit and alphabetical order.

Expected list:

Apple 1
Apple 1
Apple 1A
Apple 1B
Apple 1B
Apple 1C
Apple 1D
Apple 2
Apple 2A
Apple 2A
Apple 2C
Apple 4
Apple 5
Apple 8D
Apple 10
Apple 11
Banana 1
Banana 4
Banana 9C
Banana 9D
Banana 9E
Banana 13
Banana 16

I have tried this solution, but it orders all items by the item begins with 0-9 digit like below:

private List<Location> sortLocationList(List<Location> locationArrayList){
  Collections.sort(locationArrayList, new Comparator<Location>(){
    @Override
    public int compare(Location o1, Location o2){
      return o1.getValue().compareToIgnoreCase(o2.getValue());
    }
  });
  return locationArrayList;
}

public class Location{

  public enum LocationType{ADDRESS, STREET, CITY}

  private JavascriptObject object;
  private LocationType locationType;
  private String value;

  public Location(LocationType locationType, String value, JavascriptObject object){
    this.locationType = locationType;
    this.value = value;
    this.object = object;
  }
}

My solution is returning this:

Apple 1
Apple 1
Apple 10
Apple 11
Apple 1A
Apple 1B
Apple 1B
Apple 1C
Apple 1D
Apple 2
Apple 2A
Apple 2A
Apple 2C
Apple 4
Apple 5
Apple 8D
Banana 1
Banana 13
Banana 16
Banana 4
Banana 9C
Banana 9D
Banana 9E

Any better solution to sort this list?

Thanks in advance.

like image 668
Almett Avatar asked Jan 03 '19 17:01

Almett


2 Answers

I assume that there will always be a pattern like:

"something something"

for all the values that the getValue() method returns
and that the 2nd "something" will always start with a number with or without trailing chars.
The code below splits every such value in 3 parts and compares
the 1st part alphabetically
the 2nd part numerically and
the 3d part alphabetically:

private List<Location> sortLocationList(List<Location> locationArrayList){
    Collections.sort(locationArrayList, new Comparator<Location>(){
        @Override
        public int compare(Location o1, Location o2){
            String s1 = o1.getValue();
            String s2 = o2.getValue();

            if (s1.equalsIgnoreCase(s2))
                return 0;

            String[] tokens1 = s1.split(" ");
            String[] tokens2 = s2.split(" ");

            if (!tokens1[0].equalsIgnoreCase(tokens2[0]))
                return s1.compareToIgnoreCase(s2);

            int number1 = Integer.parseInt(tokens1[1].replaceAll("\\D", ""));
            int number2 = Integer.parseInt(tokens2[1].replaceAll("\\D", ""));

            if (number1 != number2)
                return number1 - number2;

            String suffix1 = tokens1[1].replaceAll("\\d", "");
            String suffix2 = tokens2[1].replaceAll("\\d", "");

            return suffix1.compareToIgnoreCase(suffix2);
        }
    });

    return locationArrayList;
}
like image 143
forpas Avatar answered Oct 06 '22 00:10

forpas


in alphabetical sort, the letters are after than numbers and '2' after than '10' You need sort by a name, number and suffix(String nullable), use a new class instead a String' with this attributes (name, number and suffix)

// change String to a new type
private Product value;

and fix your sort

@Override
   public int compare(Location o1, Location o2){
      int c;
      // compare name
      c = o1.getValue().getName().compareTo(o12.getValue().getName());
      if (c == 0) {
           // if is the same name compare number
           c = o1.getValue().getNum().compareTo(o2.getValue().getNum());
               if (c ==0 && o1.getValue().getSufix() != null) {
               // if is the same number compare suffix
               c = o1.getValue().getSufix().compareTo(o2.getValue().getSufix());
           }
      }
      return c;
   }
like image 44
imperezivan Avatar answered Oct 06 '22 00:10

imperezivan