Ivar Reukers
Ivar Reukers

Reputation: 7719

Kotlin - Sort List by using formatted date string (functional)

I'm trying to create a Kotlin REST API, which retrieves values from a PostgreSQL database. Now the values in these results are f.e. "14-10-2016 | 15:48" and "01-08-2015 | 09:29" So the syntax basically is dd-MM-yyyy | hh:mm

Now what I'm trying to do is create a function that will order them by date placed. (Assume these strings are in an array)

var list = listOf("14-10-2016 | 15:48",
                  "01-08-2015 | 09:29",
                  "15-11-2016 | 19:43")

What would be the cleanest (and most functional) way of sorting these? (so f.e. is there a way where I don't have to take substrings of the day, month, etc. cast them to an Int, compare them in a nested loop and write the results to a different array? (that's the only way I could think of).

Upvotes: 12

Views: 23226

Answers (4)

elect
elect

Reputation: 7190

Another alternative to the excellent Saravana answer (for minimalist and compact freaks like me..) is:

val cmp = compareBy<String> { LocalDateTime.parse(it, DateTimeFormatter.ofPattern("dd-MM-yyyy | HH:mm")) }

list.sortedWith(cmp).forEach(::println)

01-08-2015 | 09:29
14-10-2016 | 15:48
15-11-2016 | 19:43

Ps: it is the default variable for single inputs

Upvotes: 4

Raj008
Raj008

Reputation: 3927

If you are using a custom object dates list sorted as below.

println("--- ASC ---")  
dates.sortBy { it.year }
println("--- DESC ---")
dates.sortByDescending { it.year }

You can use sortByDescending {it.field} for descending order.

Upvotes: 0

Gary LO
Gary LO

Reputation: 1033

More than one approach can be used. It depends on how you process after you get the sorted result.

Points to note:

  • java.time.LocalDateTime has already implemented java.lang.Comparable<T> Interface. We can use the kotlin stdlib List.sortBy to sort the List<LocalDateTime> directly.

Ref:

// https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/sorted-by.html
fun <T, R : Comparable<R>> Iterable<T>.sortedBy(
    selector: (T) -> R?
): List<T>

The easiest way is to transform the String -> java.time.LocalDateTime and use the List.sortBy directly.

The whole implementation could be like this:

 import java.time.LocalDateTime
 import java.time.format.DateTimeFormatter

 ...


// Create a convert function, String -> LocalDateTime
val dateTimeStrToLocalDateTime: (String) -> LocalDateTime = {
    LocalDateTime.parse(it, DateTimeFormatter.ofPattern("dd-MM-yyyy | HH:mm"))
}

val list = listOf("14-10-2016 | 15:48",
        "01-08-2015 | 09:29",
        "15-11-2016 | 19:43")

// You will get List<LocalDateTime> sorted in ascending order
list.map(dateTimeStrToLocalDateTime).sorted()

// You will get List<LocalDateTime> sorted in descending order
list.map(dateTimeStrToLocalDateTime).sortedDescending()

// You will get List<String> which is sorted in ascending order
list.sortedBy(dateTimeStrToLocalDateTime)

// You will get List<String> which is sorted in descending order
list.sortedByDescending(dateTimeStrToLocalDateTime)

If you want to use org.joda.time.DateTime, you can just make a tiny change on the convert function.

A friendly reminder, always pick val as your first choice in Kotlin :).

Upvotes: 13

Saravana
Saravana

Reputation: 12817

You could use DateTimeFormatter to parse and then compare with LocalDateTime

    List<String> dates = Arrays.asList("14-10-2016 | 15:48", "01-08-2015 | 09:29", "15-11-2016 | 19:43");
    DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd-MM-yyyy | HH:mm");
    List<LocalDateTime> dateTimes = dates.stream().map(date -> LocalDateTime.parse(date, formatter)).sorted().collect(Collectors.toList());
    System.out.println(dateTimes);

Output

[2015-08-01T09:29, 2016-10-14T15:48, 2016-11-15T19:43]

Update

You could simply convert to LocalDateTime in Comparator alone

List<String> sortedDates = dates.stream().sorted(Comparator.comparing(date -> LocalDateTime.parse(date, formatter))).collect(Collectors.toList());

output

[01-08-2015 | 09:29, 14-10-2016 | 15:48, 15-11-2016 | 19:43]

Upvotes: 0

Related Questions