【问题标题】:Java sort an array of months into multiple arrays by monthJava按月份将月份数组排序为多个数组
【发布时间】:2015-09-24 02:40:17
【问题描述】:

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

【问题讨论】:

  • 仅按月还是按年/月?例如。 Jan 15 2014Jan 23 2015 是否应该合并?数组是否总是排序的,或者日期可以是随机顺序吗?
  • 也许你应该使用 > 的地图。认为它会更好地为您服务。
  • 为什么不只是使用像List&lt;List&lt;Dates&gt;&gt; 这样的列表列表,每个月从 0 到 11 将对应于适当的索引,即所有 1 月份的日期都在索引 0 中。
  • 是的,我同意,使用List&lt;List&lt;Dates&gt;&gt; 将大大解决问题
  • @WayWay 请通过编辑您的问题而不是作为 cmets 发布来发布更多信息/说明。

标签: java android arrays date


【解决方案1】:

您在正确的轨道上,但将年/月字符串化是一种缓慢的方式,只需跟踪年和月:

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

请注意,参数必须预先排序。问题 + cmets 在这一点上有点不清楚。

测试代码

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

【讨论】:

    【解决方案2】:

    使用java 8 Collectors.groupingBy,它返回一个map,然后获取值到List。

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

    【讨论】:

    • 问题标记为“Android”,因此 Java 8 不可用。
    • 但是你仍然可以使用 "e -> e.getYear() * 100 + e.getMonth()" 方法对日期进行排序
    【解决方案3】:

    乔达时间

    对于 Android,您应该使用 Joda-Time 库,而不是已证明非常麻烦的旧 java.util.Date/.Calendar 类。请注意,已经发布了一些替代版本的 Joda-Time,以解决 Android 初始运行缓慢的问题。

    Joda-Time 包含一个类YearMonth,正是我们需要将年份和月份表示为跟踪日期值的关键。 Joda-Time 也有一个类 LocalDate 来表示没有任何时间或时区的仅日期值。

    我们使用模式"MMMM dd yyyy" 定义一个formatter 来解析字符串。请注意,我们在格式化程序上指定了 LocaleEnglish 语言,因此此代码将在当前默认语言环境具有非英语语言的 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 );
    

    运行时。

    输入:[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.time

    在 Java 8 及更高版本中,您可以使用新的内置 java.time 框架。 Joda-Time 为该框架提供了灵感。在这个答案的情况下,代码将非常相似。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2018-06-23
      • 1970-01-01
      • 2014-01-25
      • 2012-07-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多