我在Java中有一个包含一组随机日期的数组:
{2015年1月20日,2015年2月12日,2015年2月20日,2015年6月21日, 2015年7月12日,2015年7月28日,2015年7月30日,2015年9月24日,2015年12月31日}
如何按月将此数组拆分为多个数组?
我想要
{{2015年1月20日},{2015年2月12日,2015年2月20日},{2015年6月21日}, {2015年7月12日,2015年7月28日,2015年7月30日},{2015年9月24日},{2015年12月31日}}
我可以遍历整个数组并检查下一个日期是否仍在同一个月内,然后将其添加到子数组中(如果是)。但是我想知道是否有更简洁或有效的方法。
修改
此外,我需要按年份和月份排序,因此,例如,2014年1月15日和2015年1月23日不应合并。
这是我提出的一种方法,但它看起来并不十分高效:
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);
}
答案 0 :(得分:2)
你走在正确的轨道上,但是将年份/月份字母化是缓慢的方式,只需跟踪年份和月份:
@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
答案 1 :(得分:0)
使用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());
答案 2 :(得分:0)
对于Android,您应该使用Joda-Time库而不是旧的java.util.Date/.Calendar类,这些类已被证明是如此麻烦。请注意,Joda-Time的一些备用版本已经发布,以解决Android问题,并且最初速度很慢。
Joda-Time包含一个班级YearMonth
,正是我们需要将年份和月份作为跟踪日期值的关键。 Joda-Time还有一个类LocalDate
来表示没有任何时间或时区的仅限日期的值。
我们使用模式"MMMM dd yyyy"
定义formatter来解析字符串。请注意,我们在格式化程序上指定了Locale语言English,因此此代码将在JVM上成功运行,其中当前默认语言环境的语言不是英语。解析“1月”,“2月”等月份的名称时,语言是否适用。
我们将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 );
跑步时。
输入:[2015年1月20日,2015年2月12日,2015年2月20日,2015年6月21日,2015年7月12日,2015年7月28日,2015年7月30日,2015年9月24日,2015年12月31日)
地图:{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 8及更高版本中,您可以使用新的内置java.time框架。 Joda-Time为该框架提供了灵感。在本答案中,代码非常相似。