【问题标题】:Transform Map Values to Data Class in Kotlin在 Kotlin 中将映射值转换为数据类
【发布时间】:2022-01-06 22:56:51
【问题描述】:

我有一张地图,其值是不同对象类型(LocalDate、LocalTime、Float、List(Float))的数组列表。

我想将地图值转换为我创建的自定义数据类。

我已经尝试解构映射值组件,但是我收到错误“解构 Map.Entry 类型的声明初始化程序必须具有 'component3()' 函数”。

我将如何在下面执行此转换?

块引用

    val localDate1 = LocalDate.now()
    val localTime1 = LocalTime.now()
    val float1 = 1f
    val floatList1 = listOf<Float>(1f, 2f, 3f)

    val localDate2 = LocalDate.now()
    val localTime2 = LocalTime.now()
    val float2 = 2f
    val floatList2 = listOf<Float>(4f, 5f, 6f)

    val myMap = HashMap<String, Any>()
    myMap["keyOne"] = arrayListOf<Any>(localDate1, localTime1, float1, floatList1)
    myMap["keyTwo"] = arrayListOf<Any>(localDate2, localTime2, float2, floatList2)

    val newMap = myMap.mapValues { (date, time, float, floatList) -> /*Here i am getting destructuring error*/
        CustomObject(
            date,
            time,
            float,
            floatList
        )
    }

块引用

data class CustomObject (
    val date: LocalDate,
    val time: LocalTime,
    val float: Float,
    val floatList: List<Float>
)

【问题讨论】:

    标签: kotlin collections


    【解决方案1】:

    Map.mapValues() 接受一个 lambda,其接收者是映射 Entry,而不是它的值。 (该方法是根据 lambda 的结果命名的,而不是它的参数。) 所以你不能这样解构它。

    还有类型转换问题:myMap 是一个映射,其值为 Any,但您似乎假设每个值实际上是 ListAny (实际元素是适当的按适当的顺序输入)。所以你需要做必要的转换来告诉编译器它们是什么类型(或者至少,你假设它们是什么类型......)

    因此您可以将其分解为一个单独的步骤,例如:

    val newMap = myMap.mapValues { entry ->
        val (date, time, float, floatList) = entry.value as List<Any>
    
        CustomObject(
            date as LocalDate,
            time as LocalTime,
            float as Float,
            floatList as List<Float>
        )
    }
    

    或者你可以直接使用数组值:

    val newMap = (myMap as Map<String, List<Any>>).mapValues {
        CustomObject(
                it.value[0] as LocalDate,
                it.value[1] as LocalTime,
                it.value[2] as Float,
                it.value[3] as List<Float>
        )
    }
    

    但是,我认为首先避免使用列表会好得多。你需要大量额外的代码来创建列表然后转换它们——但大部分代码是不安全的:如果列表不够长,每次解构都可能失败并出现异常(可能是 ArrayIndexOutOfBoundsException),并且每次转换都可以以 ClassCastException 失败。演员表总是一种代码味道,尤其是像这样的未经检查的; Kotlin 的类型系统足够强大,可以表达您可能想要的大部分内容,因此像这样绕过它往往表明设计可以改进。

    因此,如果有任何方法可以让您直接创建自定义对象,那么它可能会更短、更安全、更快且更易于阅读。

    【讨论】:

    • 当我尝试您的选项 1 方法时出现以下错误“Any 类型的解构声明初始化程序必须具有 'component1()' 函数”。我对组件 2/3/4 有相同的消息。这里有什么遗漏吗?
    【解决方案2】:
    import java.time.LocalDate
    import java.time.LocalTime
    
    data class CustomObject(
      val date: LocalDate,
      val time: LocalTime,
      val float: Float,
      val floatList: List<Float>
    )
    
    val myMap = mapOf(
      "keyOne" to listOf(LocalDate.now(), LocalTime.now(), 1f, listOf(1f, 2f, 3f)),
      "keyTwo" to listOf(LocalDate.now(), LocalTime.now(), 2f, listOf(4f, 5f, 6f))
    )
    
    val newMap = myMap.mapValues {
      CustomObject(
        it.value[0] as LocalDate,
        it.value[1] as LocalTime,
        it.value[2] as Float,
        (it.value[3] as List<*>).map { fl -> fl as Float }
      )
    }
    
    println(newMap)
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-10-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多