WayWay WayWay - 4 months ago 22
Android Question

Java sort an array of months into multiple arrays by month

I have an array in Java containing a set of random dates:


{ January 20 2015, February 12 2015, February 20 2015, June 21 2015,
July 12 2015, July 28 2015, July 30 2015, September 24 2015, December 31 2015 }


How do I split this array into multiple arrays by month?

I would want


{ {January 20 2015}, {February 12 2015, February 20 2015}, {June 21 2015},
{July 12 2015, July 28 2015, July 30 2015}, {September 24 2015}, {December 31 2015} }


I could iterate through the entire array and checking if the next date is still within the same month and then add it to the sub array if it is. However I was wondering if there was a more succinct or efficient method.

Edit:

Additionally, I need to sort by year and month so, for example, January 15 2014 and January 23 2015 should not be combined.

Here's a method I came up with but it doesn't look terribly efficient:

private void splitListByMonth(){
ArrayList<ArrayList<Homework>> mainArrayList = new ArrayList<>();
ArrayList<String> titleList = new ArrayList<>();

Calendar calendar = Calendar.getInstance();
SimpleDateFormat dateFormat = new SimpleDateFormat("MMMM yyy");
for(Homework homework:mList){
calendar.setTimeInMillis(homework.getDate());
String monthString = dateFormat.format(calendar.getTime());

if(titleList.contains(monthString)){
int index = titleList.indexOf(monthString);
mainArrayList.get(index).add(homework);
} else {
titleList.add(monthString);
int index = titleList.indexOf(monthString);
mainArrayList.get(index).add(homework);
}
}
Log.d("Tag",""+titleList);
Log.d("Tag",""+mainArrayList);
}

Answer

You're on the right track, but stringifying the year/month is the slow way, just track the year and month:

@SuppressWarnings("null")
private static List<List<Date>> splitByMonth(Date ... dates) {
    List<List<Date>> datesByMonth = new ArrayList<>();
    List<Date> monthList = null;
    int currYear = 0, currMonth = -1;
    Calendar cal = Calendar.getInstance();
    for (Date date : dates) {
        cal.setTime(date);
        if (cal.get(Calendar.YEAR) != currYear || cal.get(Calendar.MONTH) != currMonth) {
            monthList = new ArrayList<>();
            datesByMonth.add(monthList);
            currYear = cal.get(Calendar.YEAR);
            currMonth = cal.get(Calendar.MONTH);
        }
        monthList.add(date);
    }
    return datesByMonth;
}

Note that the parameter must be pre-sorted. The question + comments were a bit unclear on that point.

Test code

public static void main(String[] args) throws Exception {
    // Build list of all dates
    String[] txtDates = { "January 20 2015", "February 12 2015", "February 20 2015", "June 21 2015",
            "July 12 2015", "July 28 2015", "July 30 2015", "September 24 2015", "December 31 2015",
            "January 15 2014", "January 15 2015" };
    SimpleDateFormat fmt = new SimpleDateFormat("MMMM d yyyy");
    Date[] allDates = new Date[txtDates.length];
    for (int i = 0; i < txtDates.length; i++)
        allDates[i] = fmt.parse(txtDates[i]);

    // Sort dates, then split them by month
    Arrays.sort(allDates);
    List<List<Date>> datesByMonth = splitByMonth(allDates);

    // Print result
    for (List<Date> dates : datesByMonth) {
        StringBuilder buf = new StringBuilder();
        for (Date date : dates) {
            if (buf.length() != 0)
                buf.append(", ");
            buf.append(fmt.format(date));
        }
        System.out.println(buf);
    }
}

Output

January 15 2014
January 15 2015, January 20 2015
February 12 2015, February 20 2015
June 21 2015
July 12 2015, July 28 2015, July 30 2015
September 24 2015
December 31 2015