转换列表,过滤掉导致异常的项目

时间:2018-05-09 09:24:46

标签: kotlin reduce higher-order-functions

如何转换此String数组:

"2018-05-08T23:22:49Z" "n/a" "2018-05-07T16:37:00Z"

使用高阶函数的Date数组,例如mapflatMapreduce

我知道使用forEach可以做到这一点,但我有兴趣参与Kotlin高阶函数:

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 */
    }
}

2 个答案:

答案 0 :(得分:3)

使用mapNotNull

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)

这样可以避免为列表中的每个项创建一个列表,它会将错误日期映射为null,而mapNotNull会从列表中删除空值。

使用扩展功能

您还可以将tryOrRemove解压缩为扩展函数,使代码如下所示:

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)

使用过滤器

我是根据唯一的错误日期n / a编写的,这简化了它。

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)

答案 1 :(得分:1)

您正在寻找可以为每个输入元素输出零个或一个元素的转换。这是Iterable。平面映射函数的结果必须是val dateArray = stringArray.flatMap { try { listOf(SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'", Locale.US).parse(it)) } catch (e: ParseException) { emptyList<Date>() } } ,因此:

@pwolaq

根据SimpleDateFormat的输入添加以下内容:

强烈建议提取mapNotNull实例,因为它具有重量级初始化。此外,flatMap的解决方案比inline fun <T> runOrNull(block: () -> T) = try { block() } catch (t: Throwable) { null } 更清晰,我没有意识到这一点。如果你添加一个我认为缺少Kotlin标准库的函数,这将变得特别方便:

val formatter = SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'", Locale.US)
val dateArray: List<Date> = stringArray.mapNotNull { 
    runOrNull { formatter.parse(it) } 
}

在工具箱中使用此功能,您可以说:

mapGroupsWithState