我想知道是否有办法在一个列表中合并两个(或更多)对象。
例:
我有这堂课:
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}]
答案 0 :(得分:1)
您可以使用.groupBy
按User.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
列表(我们从空[]
开始)
(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()