【问题标题】:Compare dates from a String in list比较列表中字符串的日期
【发布时间】:2020-03-05 20:06:22
【问题描述】:

我在继续时遇到问题。我有一个列表,每个位置都包含一个字符串(在短语中末尾有一个日期)

例子:

I am new here 20/8/2019 

我想以这种方式对列表进行排序: 在位置零我想要包含最旧日期的短语和以下位置日期将更新。

我尝试使用 SimpleDateFormat 和 Date,但我不知道该怎么做。

String variable, variable2, c;
int d = 0;
for(int i = 0; i < lista.size(); i++) {
    for(int j = 1; j <lista.size(); j++) {
        variable = lista.get(i);
        variable2 = lista.get(j);
        c = compareDates(variable, variable2);
        lista.add(d,c);
        d++;
    }
}

private static Date compareDates(String variable, String variable2) throws ParseException {
    SimpleDateFormat formateador = new SimpleDateFormat("dd/MM/yyyy");
    String var = formateador.format(variable);
    String var2 = formateador.format(variable2);
    if (var.before(var2)) {
        return var;
    } else {
        if (var2.before(var1)) {

        } else {

        }
        return null;
    }
}

线程“main”java.lang.Error 中的异常:未解决的编译问题: 类型不匹配:无法从日期转换为字符串

at Ejercicio.ClaseMain.leerDes(ClaseMain.java:124)

第 124 行:c = compareDates(variable, variable2);

视觉示例:列表中的每个位置都有一个带有日期的短语:

问题是,我读了一个 .txt 文件,其中有几行。 文件内容:

塞维利亚将自己保留给Apoel并赢得没有光彩的比赛;运动 Julen Lopetegui 彻底改变了 11 人,目的是让他们休息 到常客,这并没有阻止他的团队增加他的第二个 2019 年 10 月 10 日体育比赛的胜利

Banksy 的一幅描绘被黑猩猩占领的英国议会的画作,以 >1100 万的价格售出 欧元文化代表英国之家的艺术家班克斯的油画 满是黑猩猩的公地在周四的一次拍卖中名列前茅 伦敦 980 万英镑(1100 万欧元)10/2019

我用一段时间来读取文件行并将每一行保存在列表中的每个位置,我想对列表进行排序。旧日期 ---> 最近日期。

【问题讨论】:

  • 请使用 java.time API,它会更有帮助
  • 请分享lista实例化,问题似乎出在这里
  • 是否绝对确定列表中的所有字符串短语仅在末尾有日期并且格式相同dd/mm/yyyy??
  • @ambianBeing 是的,我已经用列表中的内容更新了帖子。
  • DateSimpleDateFormat 类很糟糕。避开他们。它们在几年前被 java.time 类所取代。

标签: java sorting date-parsing date-comparison


【解决方案1】:

我的解决方案是:

    List<String> lista = List.of(
            "Sevilla reserves himself to Apoel … sportyou 10/10/2019",
            "I am new here 20/8/2019",
            "A painting by Banksy … 19/10/2019");
    List<String> sortedList = lista.stream()
            .map(s -> new Object() {
                String theString = s;
                LocalDate date = extractDate(s);
            })
            .sorted(Comparator.comparing(obj -> obj.date))
            .map(obj -> obj.theString)
            .collect(Collectors.toList());
    sortedList.forEach(System.out::println);

输出如下:

I am new here 20/8/2019
Sevilla reserves himself to Apoel … sportyou 10/10/2019
A painting by Banksy … 19/10/2019

我使用的extractDate方法是:

private static Pattern datePattern = Pattern.compile("\\d{1,2}/\\d{1,2}/\\d{4}$");
private static DateTimeFormatter dateFormatter = DateTimeFormatter.ofPattern("d/M/u");

private static LocalDate extractDate(String fullString) {
    Matcher m = datePattern.matcher(fullString);
    if (m.find()) {
        String dateString = m.group();
        return LocalDate.parse(dateString, dateFormatter);
    } else {
        throw new IllegalArgumentException("String doesn’t end with a date: " + fullString);
    }
}

为了有效地对字符串进行排序——只有在有很多字符串时才重要——我提取了尾随日期并为每个字符串只解析一次(不是每次比较)。我正在解析 LocalDate 并使用它们进行排序。为了在排序后取出原始字符串,我将StringLocalDate 放入一个对象中,然后对这些对象进行排序。我可以通过这种方式使用Object 的匿名子类,这可能会让一些人感到惊讶,但它工作得很好。

我建议你不要使用SimpleDateFormatDate。这些类设计不佳且早已过时,尤其是前者,尤其是出了名的麻烦。相反,我使用LocalDateDateTimeFormatter,两者都来自现代​​Java 日期和时间API java.time。

Java 内置了不错的排序工具。如果编写自己的排序算法是为了练习,那是一个很好的练习。坦率地说,在你的分类工作之前你还有很长的路要走。您可能想阅读排序算法,在 WWW 上也有很多文章。对于生产代码,您应该依赖库方法。

链接: Oracle tutorial: Date Time 解释如何使用 java.time。

【讨论】:

    【解决方案2】:

    请不要使用旧的 Date 库,而是使用 java.time API,所以如果您使用 Java 8,您的解决方案可以是:

    String[] strs = {"20/10/2019", "5/2/2019", "12/12/2019",
            "1/8/2019", "25/12/2019", "2/1/2019", "6/9/2019"};
    DateTimeFormatter formatter = DateTimeFormatter.ofPattern("d/M/uuuu");
    List<LocalDate> collect = Stream.of(strs)
            .map(s -> LocalDate.parse(s, formatter))  // convert your strings to dates
            .sorted() // sort the dates
            .collect(Collectors.toList()); // collect the result in a collection
    

    输出

    [2019-01-02, 2019-02-05, 2019-08-01, 2019-09-06, 2019-10-20, 2019-12-12, 2019-12-25]
    

    【讨论】:

    • 但是,这些是我不知道的短语,因为我是从文件中读取的,所以我不知道它们是什么日期。我放这张图片是为了帮助你理解我。
    【解决方案3】:

    考虑到List 中的所有字符串格式相同,并且date 在拆分后的第四个索引处,如下所示

    List<String> list = new ArrayList<>();
    list.add("I am new here 20/11/2019 ");
    list.add("I am Deadpool here 20/7/2019 ");
    list.add("I am IronMan here 20/6/2019 ");
    

    现在使用比较器根据LocalDateList 进行排序

    DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd/M/yyyy");
    list.sort(Comparator.comparing(str->LocalDate.parse(str.split(" ")[4],formatter)));
    
        System.out.println(list);  //I am IronMan here 20/6/2019 , I am Deadpool here 20/7/2019 , I am new here 20/11/2019 ]
    

    【讨论】:

      【解决方案4】:

      “20/8/2019”等日期与“dd/MM/yyyy”模式不匹配。正确的格式应该是“20/08/2019”。 排序的最短解决方案是

      list.sort(Comparator.comparing(
          source -> LocalDate.parse(source, DateTimeFormatter.ofPattern("dd/MM/yyyy"))));
      

      【讨论】:

        【解决方案5】:

        发生错误是因为在compareDates 方法返回类型是Date 而返回是String

        现在来解决方案,如果目的只是从短语中提取排序日期,这应该可行。但是查看 OP 中的代码,我感觉您正在尝试对按日期排序的短语列表进行冒泡排序,这也可以按照相同的方式实现。

        重要的部分是通过Regex提取日期。

        代码:

        List<LocalDate> ld = new ArrayList<LocalDate>();
        for(int i = 0; i < lista.size(); i++){
          ld.add(getDateFromString(lista.get(i)));
        }
        //sorting the list of dates extracted
        ld = ld.stream().sorted().collect(Collectors.toCollection(ArrayList::new));
        
        private static LocalDate getDateFromString(String str){
          LocalDate d;
          //looks for pattern dd/mm/yyyy in the passed string
          Matcher m = Pattern.compile("(\\d{1,2}/\\d{1,2}/\\d{4})").matcher(str);
          if(m.find()) {
           String match = m.group(1);
           d = LocalDate.parse(match, DateTimeFormatter.ofPattern("d/MM/yyyy"));
          }
          return d;
        }
        

        注意: 这假设每个短语都有一个dd/mm/yyyy 形式的日期字符串

        【讨论】:

        • 一个很好的答案。它演示了如何从较长的字符串中提取日期,无论该字符串的外观如何,并且它使用了 java.time,现代 Java 日期和时间 API(这是我们都应该做的)。
        【解决方案6】:

        简单地说,如果您不知道日期字符串的格式,就不可能将字符串转换为日期。 “10/11/12”是 10 月 11 日还是 12 年 11 月 10 日,还是 10 年 11 月 12 日?见How to convert String to Date without knowing the format?

        在您的文本示例中,最后日期只是“10/2019”,而您使用“20/8/2019”作为另一个示例,因此您似乎有多种可能的格式。如果你能限制可能性,就有可能找到最佳匹配。

        如果您可以使用正则表达式提取该日期作为数字序列并在文本末尾使用正斜杠(请参阅ambianBeing 的答案),那么您可以尝试使用从最严格到最严格的可能格式解析此字符串最轻松,捕获“DateTimeParseException”异常并在第一次成功解析时停止。如果没有成功,请标记它,以便您确定要修复的内容 - 文本、添加新格式或更好的正则表达式。

        使用上面的示例,您可以从格式模式开始

        • dd/MM/yyyy
        • dd/M/yyyy
        • MM/yyyy

        如果一切都失败了,使用空日期来标记条目。

        如果你把它放在一个返回日期的方法中,你就可以使用流解决方案按照其他几个人的建议对列表进行排序。

        【讨论】:

          猜你喜欢
          • 2012-10-19
          • 2013-12-23
          • 2015-09-29
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多