How to convert this array of String:
"2018-05-08T23:22:49Z"
"n/a"
"2018-05-07T16:37:00Z"
to an array of Date using Higher-Order Functions such as map, flatMap or reduce?
I do know that it's possible to do that using forEach, but I'm interested to involve Kotlin Higher-Order Functions:
val stringArray
= mutableListOf("2018-05-08T23:22:49Z", "n/a", "2018-05-07T16:37:00Z")
val dateArray = mutableListOf<Date>()
stringArray.forEach {
try {
val date = SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'", Locale.US)
.parse(it)
dateArray.add(date)
} catch (e: ParseException) {
//* Just prevents app from crash */
}
}
val format = SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'", Locale.US)
val dates = listOf("2018-05-08T23:22:49Z", "n/a", "2018-05-07T16:37:00Z")
.mapNotNull {
try {
format.parse(it)
} catch (e: ParseException) {
null
}
}
println(dates)
This avoids creating a list for each item in the list, it maps the bad dates to null, and mapNotNull removes the nulls from the list.
You could also extract the tryOrRemove to an extension function, making the code look like this:
val format = SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'", Locale.US)
fun <T, U: Any> Iterable<T>.tryOrRemove(block:(T)->U): List<U> {
return mapNotNull {
try {
block(it)
} catch (ex: Throwable) {
null
}
}
}
val dates = listOf("2018-05-08T23:22:49Z", "n/a", "2018-05-07T16:37:00Z")
.tryOrRemove(format::parse)
println(dates)
I have written it based on the only bad dates being n/a, which simplifies it.
val format = SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'", Locale.US)
val dates = listOf("2018-05-08T23:22:49Z", "n/a", "2018-05-07T16:37:00Z")
.filter { it != "n/a" }
.map(format::parse)
println(dates)
You're looking for a transformation that can output zero or one element per input element. This is flatMap. The result of a flatmapping function must be an Iterable, so:
val dateArray = stringArray.flatMap {
try {
listOf(SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'", Locale.US).parse(it))
} catch (e: ParseException) {
emptyList<Date>()
}
}
Adding the following based on @pwolaq's input:
It's highly recommended to extract the SimpleDateFormat instance because it has heavyweight initialization. Further, a solution with mapNotNull is cleaner than flatMap, I wasn't aware of it. This becomes especially convenient if you add a function that I feel is missing from the Kotlin standard library:
inline fun <T> runOrNull(block: () -> T) = try {
block()
} catch (t: Throwable) {
null
}
With this in your toolbox you can say:
val formatter = SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'", Locale.US)
val dateArray: List<Date> = stringArray.mapNotNull {
runOrNull { formatter.parse(it) }
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With