如何合并ObjectsList中的两个或多个对象

时间:2018-01-08 14:16:36

标签: groovy

我想知道是否有办法在一个列表中合并两个(或更多)对象。

例:

我有这堂课:

class User {                
    String name
    Integer age
    Integer score
}

我在另一个类

上得到了这个方法
methodTest() {
    User a = new User().with{ 
        it.name = "JACK"
        it.age = 20
    }
    User b = new User().with{
        it.name = "JACK"
        it.score = 50
    }
    User c = new User().with{ 
        it.name = "TONY"
        it.age = 25
    }
    User d = new User().with{
        it.name = "TONY"
        it.score = 30
    }
    List userList = new ArrayList()
    userList.add(a)
    userList.add(b)
    userList.add(c)
    userList.add(d)
}

Tere是一种通过名称合并userList的方法吗?类似的东西:

userList = userList.mergeBy(it.name)

然后获取用户列表:

[{name:"Jack", age: 20 , score: 50},{name:"TONY", age: 25, score: 30}]

2 个答案:

答案 0 :(得分:1)

您可以使用.groupByUser.name对列表进行分组,然后应用List<User>功能将其转换为.inject。您可以在下面找到一个示例(您向我们展示的代码的固定版本):

import groovy.json.JsonOutput

class User {
    String name
    Integer age
    Integer score
}

User a = new User(name: "JACK", age: 20)
User b = new User(name: "JACK", score: 50)
User c = new User(name: "TONY", age: 25)
User d = new User(name: "TONY", score: 30)

List userList = new ArrayList()
userList.add(a)
userList.add(b)
userList.add(c)
userList.add(d)

List<User> users = userList.groupBy { it.name } // (1)
        .values() // (2)
        .inject([]) { result, users -> // (3)
            result << users.inject(new User()) { User merged, User user -> // (4)
                merged.name = user.name ?: merged.name
                merged.age = user.age ?: merged.age
                merged.score = user.score ?: merged.score
                return merged
            }
}

println JsonOutput.toJson(users)

让我们一步一步看看这里发生了什么:

  • (1)userList.groupBy { it.name }生成以下地图:

    [JACK:[User(JACK, 20, null), User(JACK, null, 50)], TONY:[User(TONY, 25, null), User(TONY, null, 30)]]
    
  • (2)在此地图上调用.values()会返回一个用户列表列表:

    [[User(JACK, 20, null), User(JACK, null, 50)], [User(TONY, 25, null), User(TONY, null, 30)]]
    
  • (3)然后.inject([]) { result, users -> /* ... */ }收集每个用户列表,应用转换并将结果添加到result列表(我们从空[]开始)

    < / LI>
  • (4)这里我们在用户列表上调用另一个.inject()函数(此用户列表包含具有相同名称的用户列表,例如[JACK:[User(JACK, 20, null), User(JACK, null, 50)])。我们从一个新的“空”用户(.inject(new User()))开始。我们通过闭包内的merged变量访问它 - 这个变量保存.inject()函数内每次迭代的最后结果。所以它从这个空的用户开始,得到第一个,设置名称和年龄(分数未设置,因为它是null),然后它获得第二个用户,设置名称(相同的一个)和得分(年龄)未设置,因为此用户的年龄为null。使用左移操作符User将最终result添加到<<列表。

最后,当您打印以控制最终的users列表时,您将看到所需的输出:

[{"age":20,"score":50,"name":"JACK"},{"age":25,"score":30,"name":"TONY"}]

最后的注释

当然,您可以使此代码更简单,例如您可以向合并两个用户实例的User类添加一个方法,如:

import groovy.json.JsonOutput

class User {
    String name
    Integer age
    Integer score

    User merge(User user) {
        return new User(
                name: user.name ?: name,
                age: user.age ?: age,
                score: user.score ?: score
        )
    }
}

List<User> userList = [
        new User(name: "JACK", age: 20),
        new User(name: "JACK", score: 50),
        new User(name: "TONY", age: 25),
        new User(name: "TONY", score: 30)
]

List<User> users = userList.groupBy { it.name }
        .values()
        .inject([]) { result, users ->
            result << users.inject(new User()) { User merged, User user -> merged.merge(user) }
        }

println JsouOutput.toJson(users)

答案 1 :(得分:0)

使用一些简单的groovy魔法:

class User{  
   String name
   Integer age
   Integer score
   String toString(){ "$name:$age:$score" }
} 

        User a = new User(
            name:"JACK",
            age : 20
        )
        User b = new User(
            name : "JACK",
            score :50
        )
        User c = new User(
            name : "TONY",
            age : 25
        )
        User d = new User(
            name : "TONY",
            score : 30
        )
        List userList = [ a, b, c, d ]

 def mergedList = userList.inject( [:].withDefault{ new User() } ){ res, User u ->
   res[ u.name ].name = u.name
   if( u.age ) res[ u.name ].age = u.age
   if( u.score ) res[ u.name ].score = u.score
   res
 }.values()

 assert '[JACK:20:50, TONY:25:30]' == mergedList.toString()