【问题标题】:Kotlin - Merge two data classKotlin - 合并两个数据类
【发布时间】:2022-01-12 05:14:19
【问题描述】:

数据类

data class A(
    var data: List<Data>
) {
    data class Data(
        var key: String,
        var count: Long = 0,
        var sub: List<Data>? = null
    )
}

以 json 表示的类数据值。

[
  {
    "data": [
      {
        "key": "ALLOGENE THERAPEUTICS",
        "count": 47,
        "sub": [
          {
            "key": "N",
            "count": 46,
            "sub": [
              {
                "key": "S1",
                "count": 1
              },
              {
                "key": "S2",
                "count": 13
              }
            ]
          },
          {
            "key": "B+",
            "count": 1,
            "sub": [
              {
                "key": "S1",
                "count": 2
              },
              {
                "key": "S2",
                "count": 1
              }
            ]
          }
        ]
      },
      {
        "key": "CELLECTIS",
        "count": 5,
        "sub": [
          {
            "key": "B+",
            "count": 2,
            "sub": [
              {
                "key": "S1",
                "count": 3
              },
              {
                "key": "S2",
                "count": 5
              }
            ]
          },
          {
            "key": "B",
            "count": 2,
            "sub": [
              {
                "key": "S1",
                "count": 6
              },
              {
                "key": "S2",
                "count": 1
              }
            ]
          },
          {
            "key": "N",
            "count": 1,
            "sub": [
              {
                "key": "S1",
                "count": 8
              },
              {
                "key": "S2",
                "count": 4
              }
            ]
          }
        ]
      },
      {
        "key": "PFIZER",
        "count": 5,
        "sub": [
          {
            "key": "N",
            "count": 5,
            "sub": [
              {
                "key": "S1",
                "count": 83
              },
              {
                "key": "S2",
                "count": 1
              }
            ]
          }
        ]
      }
    ]
  }
]

我想将具有“ALLOGENE THERAPEUTICS”和“CELECTIS”键值的元素组合起来,并将键值替换为“STUB”。

元素组合时,所有的“count”值都必须组合起来。

并且必须添加不存在的元素。

因此,结果应该如下。

[
  {
    "data": [
      {
        "key": "STUB",
        "count": 52, // "ALLOGENE THERAPEUTICS"(47) + "CELECTIS"(5) = 52
        "sub": [
          {
            "key": "N", 
            "count": 47,  // 46 + 1
            "sub": [
              {
                "key": "S1",
                "count": 9
              },
              {
                "key": "S2",
                "count": 17
              }
            ]
          },
          {
            "key": "B+",
            "count": 3,
            "sub": [
              {
                "key": "S1",
                "count": 5
              },
              {
                "key": "S2",
                "count": 6
              }
            ]
          },
          {
            "key": "B",
            "count": 5,
            "sub": [
              {
                "key": "S1",
                "count": 11
              },
              {
                "key": "S2",
                "count": 7
              }
            ]
          }
        ]
      },
      {
        "key": "PFIZER",
        "count": 5,
        "sub": [
          {
            "key": "N",
            "count": 5,
            "sub": [
              {
                "key": "S1",
                "count": 83
              },
              {
                "key": "S2",
                "count": 1
              }
            ]
          }
        ]
      }
    ]
  }
]

如何使用 Kotlin 巧妙地编写代码?

供参考,数据类的值用json表示,结果值必须是数据类。

这是目前的进展:

为创建合并副本的数据创建一个函数

data class Data(
    var key: String,
    var count: Long = 0,
    var sub: List<Data> = emptyList()
) {
    fun mergedWith(other: Data): Data {
        return copy(
            count = count + other.count,
            sub = sub + other.sub
        )
    }
}

将合并列表折叠成单个数据项并将它们重新添加在一起。

val consolidatedKeys = listOf("ALLOGENE THERAPEUTICS", "CELECTIS")
val (consolidatedValues, nonconsolidatedValues) = a.data.partition { it.key in consolidatedKeys }
val consolidatedData = when {
    consolidatedValues.isEmpty() -> emptyList()
    else -> listOf(consolidatedValues.fold(A.Data("STUB", 0), A.Data::mergedWith))
}
val result = A(consolidatedData + nonconsolidatedValues)

并组合子元素。

consolidatedData.forEach { x ->
            x.sub
                .groupBy { group -> group.key }
                .map { A.Data(it.key, it.value.sumOf { c -> c.count }) }
}

这是目前的情况。

这样,深度为2的元素会正常工作,但深度为3的元素不会被添加。

例如,STUB下最多“N”被组合,但“N”下的“S1”和“S2”不被组合。

因此,以这种方式输出当前结果。

[
  {
    "data": [
      {
        "key": "STUB",
        "count": 52, <--------- WORK FINE
        "sub": [
          {
            "key": "N", 
            "count": 47, <--------- WORK FINE
            "sub": [] <--------- EMPTY !!
          },
          {
            "key": "B+",
            "count": 3, <--------- WORK FINE
            "sub": [] <--------- EMPTY !!
          },
          {
            "key": "B",
            "count": 5, <--------- WORK FINE
            "sub": [] <--------- EMPTY !!
          }
        ]
      },
      {
        "key": "PFIZER",
        "count": 5,
        "sub": [
          {
            "key": "N",
            "count": 5,
            "sub": [
              {
                "key": "S1",
                "count": 83
              },
              {
                "key": "S2",
                "count": 1
              }
            ]
          }
        ]
      }
    ]
  }
]

所有子元素如何组合实现?

【问题讨论】:

  • 请展示你到目前为止所做的事情

标签: kotlin data-class kotlin-reflect


【解决方案1】:

首先分解你的问题。您可以为创建合并副本的 Data 创建一个函数:

fun mergedWith(other: Data): Data {
    return copy(
        count = count + other.count,
        sub = when {
            sub == null && other.sub == null -> null
            else -> sub.orEmpty() + other.sub.orEmpty()
        }
    )
}

如果可能,我建议您为sub 参数使用不可为空的列表,并在其中没有任何内容时使用emptyList()。这使得它更简单,因为没有两种不同的方式来表示缺少项目,并且您不必处理可空性:

data class Data(
    var key: String,
    var count: Long = 0,
    var sub: List<Data> = emptyList()
) {
    fun mergedWith(other: Data): Data {
        return copy(
            count = count + other.count,
            sub = sub + other.sub
        )
    }
}

然后,您可以将列表拆分为您想要合并的列表与其他列表。然后将合并列表折叠成单个数据项并将它们重新添加到一起。

val consolidatedKeys = listOf("ALLOGENE THERAPEUTICS", "CELECTIS")
val (consolidatedValues, nonconsolidatedValues) = a.data.partition { it.key in consolidatedKeys }
val consolidatedData = when {
    consolidatedValues.isEmpty() -> emptyList()
    else -> listOf(consolidatedValues.fold(A.Data("STUB", 0), A.Data::mergedWith))
}
val result = A(consolidatedData + nonconsolidatedValues)

【讨论】:

  • 使用该逻辑实现时,不会添加子元素。例如,键值为“N”的子元素的 S1 不会变成 9。
  • 我添加了相关信息。
  • 嵌套有多深,还是无限深度?如果深度有限,每一层都有不同的含义,我建议每层使用不同的类,命名更清晰。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-08-15
  • 2019-06-29
  • 2016-07-30
  • 2012-10-08
  • 1970-01-01
相关资源
最近更新 更多