简体   繁体   English

Kotlin - 合并两个数据 class

[英]Kotlin - Merge two data class

Data class数据 class

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

A class data values expressed in json. A class 数据值以 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
              }
            ]
          }
        ]
      }
    ]
  }
]

I would like to combine elements with key values of "ALLOGENE THERAPEUTICS" and "CELECTIS" and replace the key value with "STUB".我想将元素与“ALLOGENE THERAPEUTICS”和“CELECTIS”的关键值结合起来,并用“STUB”替换关键值。

When the elements are combined, all the "count" values must be combined.组合元素时,必须组合所有“计数”值。

And elements that are not there must be added.并且必须添加不存在的元素。

Therefore, the results should be as follows.因此,结果应如下所示。

[
  {
    "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
              }
            ]
          }
        ]
      }
    ]
  }
]

How can I code the work neatly with Kotlin?如何使用 Kotlin 巧妙地编码工作?

For reference, the values of the data class are expressed as json, and the result value must be data class.作为参考,数据 class 的值表示为 json,结果值必须是数据 class。

This is the progress so far:这是迄今为止的进展:

create a function for Data that creates a merged copy为创建合并副本的数据创建 function

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
        )
    }
}

fold the consolidation list into a single data item and add them back together.将合并列表折叠成单个数据项并将它们重新添加到一起。

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)

And combine the sub-elements.并结合子元素。

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

This is the current situation.这是目前的情况。

In this way, elements with depth of 2 will work normally, but elements with depth of 3 will not be added.这样,深度为2的元素会正常工作,但深度为3的元素不会被添加。

For example, up to "N" below STUB is combined, but "S1" and "S2" below "N" are not combined.例如,STUB 下最多“N”被组合,但“N”下的“S1”和“S2”不被组合。

Therefore, the current result is output in this way.因此,这种方式当前的结果是output。

[
  {
    "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
              }
            ]
          }
        ]
      }
    ]
  }
]

How can all the sub-elements be combined and implemented?所有的子元素如何组合和实现?

First break down your problem.首先分解你的问题。 You can create a function for Data that creates a merged copy:您可以为创建合并副本的数据创建 function:

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()
        }
    )
}

I recommend if possible that you use a non-nullable List for your sub parameter, and use emptyList() when there's nothing in it.如果可能,我建议您为sub参数使用不可为空的 List,并在其中没有任何内容时使用emptyList() This makes it simpler since there aren't two different ways to represent a lack of items and you won't have to deal with nullability:这使得它更简单,因为没有两种不同的方式来表示缺少项目,并且您不必处理可空性:

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
        )
    }
}

Then you can split your list into ones that you want to consolidate vs. the rest.然后,您可以将列表拆分为您想要合并的列表与 rest。 Then fold the consolidation list into a single data item and add them back together.然后将合并列表折叠成单个数据项并将它们重新添加在一起。

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)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM