简体   繁体   中英

Compare dates from a String in list

I'm having a problem continuing. I have a list and in each position contains a String (within the phrase there is at the end a date)

Example:

I am new here 20/8/2019 

I want to sort the list this way: In position zero I want the phrase containing the oldest date and the following positions the date will be more recent.

I tried to use SimpleDateFormat and Date, but I didn't know how to do it.

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

Exception in thread "main" java.lang.Error: Unresolved compilation problem: Type mismatch: cannot convert from Date to String

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

Line 124: c = compareDates(variable, variable2);

Visual example: Each position in the list has a phrase with a date:

在此处输入图像描述

The thing is, I read a.txt file, where there are several lines. Contents of the file:

Sevilla reserves himself to Apoel and wins without brilliance; sport Julen Lopetegui revolutionized the eleven with the aim of giving rest to the regulars, which did not prevent his team from adding his second triumph of the competition sportyou 10/10/2019

A painting by Banksy of the British Parliament occupied by chimpanzees, sold >for 11 million euros culture An oil of artist Banksy representing the British House of Commons full of chimpanzees was topped on Thursday at an auction in London for 9.8 million pounds (11 million euros) 10/2019

I use a while to read the file line and save each line at each position in the list, and I want to sort the list. Old date ---> recent date.

Please don't use the legacy Date library, instead use java.time API, so if you are using Java 8 your solution can be:

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

Output

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

Considering all the strings in List are of same format and having date at fourth index after split, like below

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

Now use comparator to sort the List based on LocalDate

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 ]

My solution would be:

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

Output from this is:

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

The extractDate method that I am using is:

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

For efficient sorting of the strings — it only matters if there are many — I am extracting the trailing date and parsing it only once for each string (not for every comparison). I am parsing into LocalDate and use these for sorting. In order to get the original strings out after sorting I have put both the String and the LocalDate into an object and then sort these objects. It may surprise some that I can use an anonymous subclass of Object in this way, but it works nicely.

I recommend you don't use SimpleDateFormat and Date . Those classes are poorly designed and long outdated, the former in particular notoriously troublesome. Instead I am using LocalDate and DateTimeFormatter , both from java.time, the modern Java date and time API.

Java has nice sorting facilities built-in. If writing your own sorting algorithm was for an exercise, that's a good exercise. Frankly you still had a way to go before your sorting would work. You may want to read up on sorting algorithms, there's a lot written, also on the WWW. For production code you should rely on a library method.

Link: Oracle tutorial: Date Time explaining how to use java.time.

The dates like "20/8/2019" are not matching the pattern "dd/MM/yyyy". The correct format should be like "20/08/2019". And the shortest solution for sorting is

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

The error is happening because at compareDates the method return type is Date while the returns are String .

Now coming to the solution, if the intent is to just get the sorted dates extracted from the phrases this should work. But looking at the code in OP I sense you're trying to bubble sort the list of phrases sorted by dates which can also be achieved following the same lines.

The important part is extraction of the date via Regex .

Code:

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

Note: This takes the assumption that every phrase will have one date string in the form of dd/mm/yyyy

Simply, if you don't know the format of the date strings, its not possible to convert the strings to dates. Is "10/11/12" the 11 of October or the 10th of November of year '12 or is it the 12 of November of year '10? See How to convert String to Date without knowing the format? .

In your text example, the last date is simply "10/2019" and you used "20/8/2019" as another example so it seems you have a mix of possible formats. If you could limit the possibilities, it might be possible to find the best match.

If you can extract that date using regex as a sequence of numbers and forward slashes at the end of the text (see answer from ambianBeing ), then you could try to parse this string using the possible formats from most strict to most relaxed, trapping the 'DateTimeParseException' exceptions and stopping at the first successful parse. If nothing succeeds, flag it so you can determine what to fix - either the text, add a new format or a better regex expression.

Using the examples above, you could start with format patterns

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

If everything fails, use a null date to flag the entry.

If you put this in a method that returns the date, you can then use the stream solution to sort the list as suggested by several others.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM