1

I have an ArrayList<String>. The entries in the list can be of the following form:

42356_11_1_9345668
562834_12_1_8674852_8
52423_4_2_586284_2
5234_13_9_535567

As you can see the middle part contains the date: xx_y is the day and the month. The other values to the left and right can be of arbitray length. Some Strings have one last additional digit.

I would like to sort the list first according to month (y in xx_y) and then according to day (xx in xx_y). Of course it is possible that the month and day are equal. In this case it should additionally be sorted according to the number following the month (e.g. 8674852 in the second example).

How can this be done? If it is easier with other data structures, this is ok, I'm flexible.

machinery
  • 5,972
  • 12
  • 67
  • 118
  • Check out Java Sorting with the [Collection Class](http://stackoverflow.com/questions/6957631/sort-java-collection). it might be worthwhile to create a new class that represents this data structure rather than strings. The comparisons may be faster that way. – JCOC611 Feb 11 '16 at 22:53

2 Answers2

1

If you can put these into other data structures, you definitely should. Parsing a string every time you want to do something with it is painful.

public class Entry implements Comparable<Entry>    // Pick a more descriptive name
{
    int firstNumber;
    int month;
    int day;
    int lastNumber;

    public int compareTo(Entry other)
    {
        int comparison = month - other.month;
        if (comparison == 0)
            comparison = day - other.day;
        return comparison;
    }
}

Make a list of these entries, and then use the Collections methods to sort it:

Collections.sort(list);
Andrew Williamson
  • 8,299
  • 3
  • 34
  • 62
  • Don't use `int` for `firstnumber` and `lastnumber` unless you KNOW the number will always be numbers between 0 and `Integer.MAX_VALUE`. Using `int` here is exactly equivalent to "It's 1966, use only two digits for the year because we haven't thought of Y2K yet" – Jim Garrison Feb 11 '16 at 23:09
  • This is just a quick example to show how to create a custom data type, and sort on multiple fields. – Andrew Williamson Feb 11 '16 at 23:22
  • Thank you very much for the example. This is great for sorting but what when I would like to access directly an Entry with a specific month and day? Do I have to iterate over the whole sorted list? – machinery Feb 12 '16 at 21:50
  • You can use [Collections.binarySearch](https://docs.oracle.com/javase/7/docs/api/java/util/Collections.html#binarySearch(java.util.List,%20T,%20java.util.Comparator)) on the sorted list. – Andrew Williamson Feb 13 '16 at 00:38
1

Given the following Entry class:

public class Entry{
   public String getItem(){...}
   public MonthDay getMonthDay(){...}
   public int getNumber(){...}

   public static Entry parseItem(String item){...}
}

You can use the following (untested!):

List<String> sortedItems = items.stream()
    .map(Entry::parseItem)
    .sort(Comparator.comparing(Entry::getMonthDay)
              .thenComparingInt(Entry::getNumber))
    .map(Entry::getItem)
    .collect(Collectors.toList);
Puce
  • 37,247
  • 13
  • 80
  • 152