Take the 2-minute tour ×
Stack Overflow is a question and answer site for professional and enthusiast programmers. It's 100% free, no registration required.

I hava an ArrayList of String values (they need to be formatted as such) which I need to sort by year. The list looks like:

01-05-2011
11-24-2011
01-12-2012
...

I currently have them sorted alphabetically by month, but I was wondering how I can sort this ArrayList of Strings by year.

share|improve this question

5 Answers 5

up vote 7 down vote accepted
Collections.sort(
    myList, new Comparator<String>() {
      @Override
      public int compare(String a, String b) {
        // If a is "11-24-2012", then aLastDash points
        // here ---------^.
        int aLastDash = a.lastIndexOf("-");
        int bLastDash = b.lastIndexOf("-");
        return a.substring(aLastDash+1).compareTo(
               b.substring(bLastDash+1));
      }
    });

Collections.sort takes a Comparator that specifies how to compare two list values. The list values in your case are Strings. You can just compare the last 4 digits of each string lexicographically and you're done.

Collections.sort is stable, so if your strings are already sorted by month, and you sort by year, groups of strings with the same year will still be sorted by month.

Ideally though, you should convert your list to a list of something other than strings, for example, Joda time dates. Right now this code is stringly typed. The sooner you take inputs and coerce them to meaningful objects, the less of your code has to make input assumptions the fewer lines of code you have to debug when your assumptions don't quite hold.

share|improve this answer

I've combined 2 of the suggested solutions here..

Arrays.sort(new String[] {}, new Comparator<String>() {
        private final Pattern p = Pattern.compile("(\\d\\d)-(\\d\\d)-(\\d\\d\\d\\d)");

        @Override
        public int compare(String o1, String o2) {
            Matcher m1 = p.matcher(o1);
            Matcher m2 = p.matcher(o2);

            int compareYear = m1.group(3).compareTo(m2.group(3));
            if (compareYear == 0) {
                int compareMonth = m1.group(1).compareTo(m2.group(1));
                if (compareMonth == 0) {
                    return m1.group(2).compareTo(m2.group(2));
                } else {
                    return compareMonth;
                }

            } else {
                return compareYear;
            }

        }
    });
share|improve this answer

I wouldn't use a regex for this - basically you should implement Comparator<String> to compare any two strings. You could do that just by rearranging the bits of the string (into yyyyMMdd format for example) and then performing a lexicographic comparison, or you could parse the string as a date and compare the two dates.

Either way, you'd pass the comparator into Collections.sort().

Note that this suggestion will sort them completely - so by year, then month, then day. If you just sort by year, they still won't be in a real chronological order. I would personally go straight for doing it completely chronologically, as that's likely to cause less surprises later.

share|improve this answer
    
@John:I was wondering 1)How do you decide when a regex approach is the preferred way?2)I don't follow the part on rearranging the bits of the string and then performing a lexicographic comparison –  Cratylus Jan 24 '12 at 13:30
    
He just meant: first write your dates as 2011-05-01 instead of 01-05-2011, then use the natural lexicographic ordering. That's also what @dasblinkenlight is suggesting. Now you can do that in your list, or in your comparator (but the comparison will be slower) - And I agree, it'd be the most sensible way to sort your dates –  Guillaume Jan 24 '12 at 13:36
    
@user384706: I'd use a regular expression when I wanted to perform pattern matching. There's no real pattern matching here - there's comparison based on a pattern, but that's not the same thing. –  Jon Skeet Jan 24 '12 at 13:38
    
@user384706, regular expressions are useful for lexing strings (breaking them into chunks based on syntactic cues), and for substituting those tokens into an output template. Breaking a string into tokens does not, by itself, specify how to compare those strings, so regular expressions can only be part of the solution and do not make your code less "stringly typed". –  Mike Samuel Jan 24 '12 at 13:38

If you are set in using regexp, transform your string like this:

String toCompare = monthDayYearString.replaceAll(
    "(\\d\\d)-(\\d\\d)-(\\d\\d\\d\\d)"
,   "$3$1$2"
);

This expression captures the elements of your date, and re-orders them to bring slower-changing elements closer to the beginning of the string. Now the strings can be alphabetized to sort on the date.

share|improve this answer

Use Collections.sort and build a Comparator that uses regexes.

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.