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