I have two lists of objects with contents that look like this:
List A
id = 1, name = "alex", height = null, weight = 60
id = 2, name = "sara", height = null, weight = 50
List B
id = 1, name = "alex", height = 40, weight = null
id = 2, name = "sara", height = 30, weight = null
I can’t come up with anything good to “merge” these two lists overriding the nulls. The ideal end result would be:
id = 1, name = "alex", height = 40, weight = 60
id = 2, name = "sara", height = 30, weight = 50
I’ve been looking into Kotlin collections to see if there’s anything that would help me get closer to this but I have only been able to do this:
a.union(b).groupBy { it.id }
This returns a map with the ID as key and the full object as value… but I still need to merge the values into one object.
Is there anything that will do this that is not a very manual approach of checking nulls and picking the value in the other list?
Advertisement
Answer
I made the following (using “User” as a placeholder. Replace it with your own data structure):
List<User> ul1 = new ArrayList<>();
ul1.add(new User(1, "alex", null, 90));
ul1.add(new User(2, "sara", null, 50));
List<User> ul2 = new ArrayList<>();
ul2.add(new User(1, "alex", 40, null));
ul2.add(new User(2, "sara", 30, null));
List<User> rl = new ArrayList<>(Stream.concat(ul1.stream(), ul2.stream())
.collect(Collectors.toMap(
User::getId,
e -> e,
User::merge
)).values());
for (User u : rl) {
System.out.println(u.toString());
}
And this is the “User” class (Replace it with your own Data structure):
public static class User {
private final int id;
private final String name;
private final Integer height;
private final Integer weight;
public User(int id, String name, Integer height, Integer weight) {
this.id = id;
this.name = name;
this.height = height;
this.weight = weight;
}
public int getId() {
return id;
}
public String getName() {
return name;
}
public Integer getHeight() {
return height;
}
public Integer getWeight() {
return weight;
}
@Override
public String toString() {
return "User{" +
"id=" + id +
", name='" + name + ''' +
", height='" + height + ''' +
", weight='" + weight + ''' +
'}';
}
public static User merge(User e1, User e2) {
if (e1.id != e2.id)
throw new IllegalArgumentException();
return new User(
e1.id,
eval(e1.name, e2.name),
eval(e1.height, e2.height),
eval(e1.weight, e2.weight)
);
}
private static <T> T eval(T v1, T v2) {
return v1 != null ? v1 : v2;
}
}
The result I got was:
User{id=1, name='alex', height='40', weight='90'}
User{id=2, name='sara', height='30', weight='50'}
So I guess it works