Java сортирует массив месяцев в несколько массивов по месяцам

У меня есть массив в Java, содержащий набор случайных дат:

{20 января 2015 года, 12 февраля 2015 года, 20 февраля 2015 года, 21 июня 2015 года, 12 июля 2015 года, 28 июля 2015 года, 30 июля 2015 года, 24 сентября 2015 года, 31 декабря 2015 года}

Как разбить этот массив на несколько массивов по месяцам?

я бы хотел

{{20 января 2015 года}, {12 февраля 2015 года, 20 февраля 2015 года}, {21 июня 2015 года}, {12 июля 2015 года, 28 июля 2015 года, 30 июля 2015 года}, {24 сентября 2015 года}, {31 декабря 2015 года}}

Я мог бы перебирать весь массив и проверять, находится ли следующая дата в том же месяце, а затем добавить его в подвариантный массив, если он есть. Однако мне было интересно, был ли более краткий или эффективный метод.

Редактировать:

Кроме того, мне нужно сортировать по годам и месяцам, поэтому, например, 15 января 2014 года и 23 января 2015 года не следует комбинировать.

Вот метод, который я придумал, но он не выглядит ужасно эффективным:

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); } 

Solutions Collecting From Web of "Java сортирует массив месяцев в несколько массивов по месяцам"

Вы на правильном пути, но сокращение года / месяца – медленный путь, просто отслеживайте год и месяц:

 @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; } 

Обратите внимание, что параметр должен быть предварительно отсортирован. Вопрос + комментарии были немного неясны в этом вопросе.

Тестовый код

 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); } } 

Вывод

 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 

Используя java 8 Collectors.groupingBy, он возвращает карту, а затем получает значения 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()); 

Joda времени

Для Android вы должны использовать библиотеку Joda-Time, а не старые классы java.util.Date/.Calendar, которые оказались настолько неприятными. Обратите внимание, что некоторые альтернативные выпуски Joda-Time были выпущены для обхода проблемы Android с начальной медлительностью.

Joda-Time включает в себя класс YearMonth , именно то, что нам нужно представлять год и месяц как ключ к отслеживанию значений даты. Joda-Time также имеет класс LocalDate для представления значения только для даты без какого-либо времени или часового пояса.

Мы определяем форматтер с шаблоном "MMMM dd yyyy" для синтаксического анализа строк. Обратите внимание, что мы укажем Locale с английским языком в форматировании, чтобы этот код успешно работал на JVM, где текущий язык по умолчанию имеет язык, отличный от английского. Чем язык применяется при анализе имен месяцев «Январь», «Февраль» и т. Д.

Мы собираем значения LocalDate как SortedSet который выполняет две цели: (a) устраняет дубликаты и (b) сохраняет даты сортировки. Наша реализация SortedSet – это TreeSet . Каждому заданному объекту присваивается объект YearMonth . Треки TreeMap которых YearMonth имеет набор дат. Мы используем TreeMap вместо HashMap чтобы сохранить ключи в отсортированном порядке, поскольку он реализует SortedMap . Если у вас было огромное количество элементов и сортировка по ключу не была критичной, то HashMap мог бы стать лучшим выбором для производительности.

 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 ); } 

Дамп для консоли.

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

При запуске.

Ввод: [20 января 2015 года, 12 февраля 2015 года, 20 февраля 2015 года, 21 июня 2015 года, 12 июля 2015 года, 28 июля 2015 года, 30 июля 2015 года, 24 сентября 2015 года, 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

В Java 8 и более поздних версиях вы можете использовать новую встроенную инфраструктуру java.time. Joda-Time послужило источником вдохновения для этой структуры. Код будет очень похож в случае этого ответа.