Java sorts 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 like

{{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 over the entire array and check if the next date is in the same month, and then add it to the subvariant array, if so. However, I was wondering if there was a more concise or efficient method.

Edit:

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

Here is a method that I came up with, but it does not look terribly effective:

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); } 
+6
source share
3 answers

You're on the right track, but reducing the year / month is the slow way, just keep track of 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; } 

Please note that the parameter must be pre-sorted. Question + comments were a bit unclear in this question.

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 
+2
source

Using java 8 Collectors.groupingBy, it returns a map and then gets the values ​​of toList.

  List<List<Date>> partitions = dates.stream().collect(Collectors.groupingBy(e -> e.getYear() * 100 + e.getMonth(), TreeMap::new, Collectors.toList())).values().stream().collect(Collectors.toList()); 
0
source

Joda time

For Android, you should use the Joda-Time library, not the old java.util.Date/.Calendar classes, which have proven to be so troublesome. Please note that some alternative releases of Joda-Time have been released to work around the Android issue with initial slowness.

Joda-Time includes the YearMonth class, just what we need to represent the year and month as the key to keeping track of date values, Joda-Time also has a LocalDate class to represent the value only for a date without any time or time zone.

We define a formatter with the template "MMMM dd yyyy" for parsing strings. Please note that we specify Locale with English as the formatting language so that this code works successfully on the JVM, where the current language defaults to a language other than English. What language is used in the analysis of the names of the months "January", "February", etc.

We collect LocalDate values ​​as a SortedSet , which serves two purposes: (a) eliminates duplicates and (b) keeps dates sorted. Our implementation of SortedSet is a TreeSet . Each specified object is assigned a YearMonth object. A TreeMap keeps track of which YearMonth has a set of dates. We use TreeMap , not HashMap , to store the keys in sorted order since it implements SortedMap . If you had a huge number of elements and sorting by key was not critical, then HashMap could be the best choice for performance.

 String[] input = { "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" }; Map<YearMonth , SortedSet<LocalDate>> map = new TreeMap<>(); DateTimeFormatter formatter = DateTimeFormat.forPattern( "MMMM dd yyyy" ).withLocale( Locale.ENGLISH ); for ( String string : input ) { LocalDate localDate = formatter.parseLocalDate( string ); YearMonth yearMonth = new YearMonth( localDate ); if ( ! map.containsKey( yearMonth ) ) { // If this is the first encounter with such a year-month, make a new entry. map.put( yearMonth , new TreeSet<>() ); } map.get( yearMonth ).add( localDate ); } 

Dump for the console.

 System.out.println( "input: " + Arrays.toString( input ) ); System.out.println( "map: " + map ); 

At startup.

input: [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]

map: {2015-01 = [2015-01-20], 2015-02 = [2015-02-12, 2015-02-20], 2015-06 = [2015-06-21], 2015-07 = [ 2015-07-12, 2015-07-28, 2015-07-30], 2015-09 = [2015-09-24], 2015-12 = [2015-12-31]}

java.time

In Java 8 and later, you can use the new built-in java.time framework. Joda-Time has been an inspiration for this structure. The code will be very similar in case of this answer.

0
source

All Articles