组合/合并列表中的对象成员
Combining / merging object members in a list
我从列表中的 class A 中得到了一个对象列表。
其中一些对象的 ID 和名称相同,但在列表 中不同,列表 b 总是不同的。
我需要合并这些,以便我的列表仅由具有相同名称和 ID 的对象 a 组成,并且收集来自同一组的所有 b
我可以利用 jdk 8 plus utils,所以在这里可以使用流。虽然我认为这里的反射更有用?
PS:我无法更改 b 的 a 的内容 class 因为它们是生成的 classes 并且没有访问/扩展的可能性
@Test
public void test() {
List.of(new A(1, "a1", List.of(new B(1, "1b"))),
new A(1, "a1", List.of(new B(2, "2b"))),
new A(2, "a2", List.of(new B(3, "3b"))));
//expected
List.of(new A(1, "a1", List.of(new B(1, "1b"), new B(2, "2b"))),
new A(2, "a2", List.of(new B(3, "3b"))));
}
class A {
public A(int id, String name, List<B> listB) {
this.id = id;
this.name = name;
this.listB = listB;
}
int id;
String name;
List<B> listB;
}
class B {
public B(int id, String name) {
this.id = id;
this.name = name;
}
int id;
String name;
}
如果您需要为每个 id
保留一个实例,您可以编写(我假设对象具有 getter 和 setter)
System.out.println(xs.stream()
.collect(groupingBy(A::getId, toList()))
.values().stream()
.peek(g -> g.get(0).setListB(
g.stream()
.flatMap(h -> h.getListB().stream())
.collect(groupingBy(B::getId, toList()))
.values().stream()
.map(i -> i.get(0))
.collect(toList())))
.map(g -> g.get(0))
.collect(toList()));
你的输入案例与输出
[A(id=1, name=a1, listB=[B(id=1, name=b1), B(id=2, name=b2)]), A(id=2, name=a2, listB=[B(id=3, name=b3)])]
如果可以创建新实例,则可以重新规范化列表
System.out.println(xs.stream()
.flatMap(a -> a.getListB().stream().map(b -> List.<Object>of(a.id, a.name, b.id, b.name)))
.distinct()
.collect(groupingBy(o -> o.get(0), toList()))
.values()
.stream()
.map(zs -> new A((int) zs.get(0).get(0), (String) zs.get(0).get(1),
zs.stream().map(z -> new B((int) z.get(2), (String) z.get(3))).collect(toList())))
.collect(toList()));
(你可以使用一些叫做 DenormalizedRow
左右的中间 class 来改变丑陋的 .get(0).get(0)
)
你可以使用
record Key(int id, String name) {};
List<A> result = input.stream().collect(
Collectors.groupingBy(a -> new Key(a.getId(), a.getName()),
LinkedHashMap::new,
Collectors.flatMapping(a -> a.getListB().stream(), Collectors.toList())))
.entrySet().stream()
.map(e -> new A(e.getKey().id(), e.getKey().name(), e.getValue()))
.collect(Collectors.toList());
if(!result.equals(expected)) {
throw new AssertionError("expected " + expected + " but got " + result);
}
这会用新的 A
对象构造新列表,适用于不可变对象。您对 List.of(…)
的使用表明您偏爱不可变对象。如果你有可变对象并想就地执行操作,你可以做
List<A> result = new ArrayList<>(input); // only needed if input is an immutable list
record Key(int id, String name) {};
HashMap<Key,A> previous = new HashMap<>();
result.removeIf(a -> previous.merge(new Key(a.getId(), a.getName()), a, (old, newA) -> {
var l = old.getListB();
if(l.getClass() != ArrayList.class) old.setListB(l = new ArrayList<>(l));
l.addAll(newA.getListB());
return old;
}) != a);
if(!result.equals(expected)) {
throw new AssertionError("expected " + expected + " but got " + result);
}
这将从列表中删除重复项并将它们的 B
添加到之前遇到的原始列表中。它进行最少的更改以获得预期的列表,例如如果没有重复项,它什么也不做。
如果A
具有相同id的对象总是具有相同的名称,换句话说,不需要一个关键对象检查两者,你可以将这种方法简化为
List<A> result = new ArrayList<>(input); // only needed if input is an immutable list
HashMap<Integer,A> previous = new HashMap<>();
result.removeIf(a -> previous.merge(a.getId(), a, (old, newA) -> {
var l = old.getListB();
if(l.getClass() != ArrayList.class) old.setListB(l = new ArrayList<>(l));
l.addAll(newA.getListB());
return old;
}) != a);
if(!result.equals(expected)) {
throw new AssertionError("expected " + expected + " but got " + result);
}
我从列表中的 class A 中得到了一个对象列表。 其中一些对象的 ID 和名称相同,但在列表 中不同,列表 b 总是不同的。
我需要合并这些,以便我的列表仅由具有相同名称和 ID 的对象 a 组成,并且收集来自同一组的所有 b 我可以利用 jdk 8 plus utils,所以在这里可以使用流。虽然我认为这里的反射更有用?
PS:我无法更改 b 的 a 的内容 class 因为它们是生成的 classes 并且没有访问/扩展的可能性
@Test
public void test() {
List.of(new A(1, "a1", List.of(new B(1, "1b"))),
new A(1, "a1", List.of(new B(2, "2b"))),
new A(2, "a2", List.of(new B(3, "3b"))));
//expected
List.of(new A(1, "a1", List.of(new B(1, "1b"), new B(2, "2b"))),
new A(2, "a2", List.of(new B(3, "3b"))));
}
class A {
public A(int id, String name, List<B> listB) {
this.id = id;
this.name = name;
this.listB = listB;
}
int id;
String name;
List<B> listB;
}
class B {
public B(int id, String name) {
this.id = id;
this.name = name;
}
int id;
String name;
}
如果您需要为每个 id
保留一个实例,您可以编写(我假设对象具有 getter 和 setter)
System.out.println(xs.stream()
.collect(groupingBy(A::getId, toList()))
.values().stream()
.peek(g -> g.get(0).setListB(
g.stream()
.flatMap(h -> h.getListB().stream())
.collect(groupingBy(B::getId, toList()))
.values().stream()
.map(i -> i.get(0))
.collect(toList())))
.map(g -> g.get(0))
.collect(toList()));
你的输入案例与输出
[A(id=1, name=a1, listB=[B(id=1, name=b1), B(id=2, name=b2)]), A(id=2, name=a2, listB=[B(id=3, name=b3)])]
如果可以创建新实例,则可以重新规范化列表
System.out.println(xs.stream()
.flatMap(a -> a.getListB().stream().map(b -> List.<Object>of(a.id, a.name, b.id, b.name)))
.distinct()
.collect(groupingBy(o -> o.get(0), toList()))
.values()
.stream()
.map(zs -> new A((int) zs.get(0).get(0), (String) zs.get(0).get(1),
zs.stream().map(z -> new B((int) z.get(2), (String) z.get(3))).collect(toList())))
.collect(toList()));
(你可以使用一些叫做 DenormalizedRow
左右的中间 class 来改变丑陋的 .get(0).get(0)
)
你可以使用
record Key(int id, String name) {};
List<A> result = input.stream().collect(
Collectors.groupingBy(a -> new Key(a.getId(), a.getName()),
LinkedHashMap::new,
Collectors.flatMapping(a -> a.getListB().stream(), Collectors.toList())))
.entrySet().stream()
.map(e -> new A(e.getKey().id(), e.getKey().name(), e.getValue()))
.collect(Collectors.toList());
if(!result.equals(expected)) {
throw new AssertionError("expected " + expected + " but got " + result);
}
这会用新的 A
对象构造新列表,适用于不可变对象。您对 List.of(…)
的使用表明您偏爱不可变对象。如果你有可变对象并想就地执行操作,你可以做
List<A> result = new ArrayList<>(input); // only needed if input is an immutable list
record Key(int id, String name) {};
HashMap<Key,A> previous = new HashMap<>();
result.removeIf(a -> previous.merge(new Key(a.getId(), a.getName()), a, (old, newA) -> {
var l = old.getListB();
if(l.getClass() != ArrayList.class) old.setListB(l = new ArrayList<>(l));
l.addAll(newA.getListB());
return old;
}) != a);
if(!result.equals(expected)) {
throw new AssertionError("expected " + expected + " but got " + result);
}
这将从列表中删除重复项并将它们的 B
添加到之前遇到的原始列表中。它进行最少的更改以获得预期的列表,例如如果没有重复项,它什么也不做。
如果A
具有相同id的对象总是具有相同的名称,换句话说,不需要一个关键对象检查两者,你可以将这种方法简化为
List<A> result = new ArrayList<>(input); // only needed if input is an immutable list
HashMap<Integer,A> previous = new HashMap<>();
result.removeIf(a -> previous.merge(a.getId(), a, (old, newA) -> {
var l = old.getListB();
if(l.getClass() != ArrayList.class) old.setListB(l = new ArrayList<>(l));
l.addAll(newA.getListB());
return old;
}) != a);
if(!result.equals(expected)) {
throw new AssertionError("expected " + expected + " but got " + result);
}