Scala实战 -- 对List中的部分元素进行合并操作

2019-04-01  本文已影响0人  枫叶_huazhe

近期业务出现了一个需求,需要对一个相同实体的List中,部分实体名和id相同的元素进行合并,将其合并为一个实体,以便在业务上做统计处理,合并后的实体为合并前的实体的某些数值相加。
此需求催生了本篇文章。我们将抽象一个简单的实体来介绍,如何在Scala List 中合并部分Element 元素。

定义业务实体对象 MergeInfo

定义一个包含 name 和收入数据的实体对象,当判断两个实体的 name 相同时,我们决定对其进行合并操作,将两个实体的 fee 进行累计,完成合并。
其中 diff 方法定义了当传入的 target 对象 name 与源对象的 name 相同时,返回 true,否则返回 false
merge 操作则是当上一步 diff 返回 true 时,我们会采取的合并操作的具体逻辑。

case class MergeInfo(name: String, fee: Double) {

    //要比较的目标对象,根据什么条件确定是否需要merge
    def diff(target: MergeInfo): Boolean = {
        name == target.name
    }

    //定义合并操作
    def merge(target: MergeInfo): MergeInfo = {
        MergeInfo(name, fee + target.fee)
    }

}

使用尾递归遍历 List 并进行合并

实体逻辑定义完成后,我们通过使用尾递归的模式来遍历给定的 List
并使用 matching pattern 模式来进行合并前的判断和合并操作,
使用迭代器和累加器将遍历变为尾递归的形式,优化遍历的性能。

object Utils {
    /**
      * Merging elements in a Scala List
      */
    implicit class ElementMergeOfList(value: List[MergeInfo]) {

        def merge: List[MergeInfo] = {
            @tailrec
            def process(in: List[MergeInfo], accum: List[MergeInfo]): List[MergeInfo] = {
                in match {
                    case x :: y :: ys if x.diff(y) => process(x.merge(y) :: ys, accum)
                    case x :: xs => process(xs, x :: accum)
                    case Nil => accum
                }
            }
            process(value, Nil).reverse
        }

    }
}

程序解释:

测试程序

/**
* 将上述隐式转换类引入进来
*/
object MergeElementSpec {

    def main(args: Array[String]): Unit = {
        test1()
    }

    def test1(): Unit = {
        val mergeInfoList = List(MergeInfo("annual", 12.5),
            MergeInfo("Balance", 14.3), MergeInfo("Balance", 15.7),
            MergeInfo("Call", 21.2), MergeInfo("Call", 0.3),
            MergeInfo("Date", 45.4), MergeInfo("Element", 24)
        )

        val mergedResult: List[MergeInfo] = mergeInfoList.merge

        println(s"merge 前元素 size: ${mergeInfoList.size}, merge 后元素 size: ${mergedResult.size}")
        println(s"merge 后元素详情: $mergedResult")
    }

}

运行测试类,结果如下:

merge 前元素 size: 7, merge 后元素 size: 5

merge 后元素详情:List(MergeInfo(annial,12.5),MergeInfo(Balance,30.0),MergeInfo(Call,12.5),MergeInfo(Date,45.4),MergeInfo(Element,24.0))

上一篇 下一篇

猜你喜欢

热点阅读