I performed a query and get a result list of this object:
public MyObject {
private String key;
private String value1;
private Integer value2;
}
The results looks like this:
key value1 value2
1 WWW EEE
1 WWW AAA
2 WWW EEE
I would like to iterate this list and create a list of something like this, grouping it by key.
//first object of the list
public MyCreatedObject {
private String key; //1
private List<Value1> value1List; //WWW, WWW
private List<Value2> value2List; //EEE, AAA
}
//second object of the list
public MyCreatedObject {
private String key; //2
private List<Value1> value1List; //WWW
private List<Value2> value2List; //EEE
}
I'm tried using stream, iterating and a couple of things but I'm really struggling with this.
Can someone give me some help?
Thanks a lot folks
CodePudding user response:
Try this.
record MyObject(String key, String value1, String value2) {}
record MyCreatedObject(String key, List<String> value1List, List<String> value2List) {}
public static void main(String[] args) {
List<MyObject> list = List.of(
new MyObject("1", "WWW", "EEE"),
new MyObject("1", "WWW", "AAA"),
new MyObject("2", "WWW", "EEE"));
Map<String, MyCreatedObject> map = new LinkedHashMap<>();
for (MyObject obj : list) {
MyCreatedObject c = map.computeIfAbsent(obj.key(),
k -> new MyCreatedObject(k, new ArrayList<>(), new ArrayList<>()));
c.value1List().add(obj.value1());
c.value2List().add(obj.value2());
}
List<MyCreatedObject> result = new ArrayList<>(map.values());
for (MyCreatedObject obj : result)
System.out.println(obj);
}
output:
MyCreatedObject[key=1, value1List=[WWW, WWW], value2List=[EEE, AAA]]
MyCreatedObject[key=2, value1List=[WWW], value2List=[EEE]]
CodePudding user response:
You can use MyCreatedObject
as a collector by adding a couple of methods:
static Collector<MyObject, ?, MyCreatedObject> collector() {
return Collector.of(MyCreatedObject::new, MyCreatedObject::add, MyCreatedObject::merge);
}
void add(MyObject o) {
key = o.key;
value1List.add(o.value1);
value2List.add(o.value2);
}
MyCreatedObject merge(MyCreatedObject other) {
key = other.key;
value1List.addAll(other.value1List);
value2List.addAll(other.value2List);
return this;
}
Then use it as a downstream collector for groupingBy()
:
Map<String, MyCreatedObject> grouped = list.stream()
.collect(Collectors.groupingBy(o -> o.key, MyCreatedObject.collector()));
Alternatively, you can convert add()
to a constructor and group using toMap()
:
Map<String, MyCreatedObject> grouped = list.stream()
.collect(Collectors.toMap(o -> o.key, MyCreatedObject::new, MyCreatedObject::merge));
CodePudding user response:
Collectors.toMap
with the merge function may be used to build a map Map<String, MyCreatedObject>
and then convert its values to the list, providing that appropriate all-args constructor of MyCreatedObject
is provided:
List<MyObject> input = ... ; // setup input data
List<MyCreatedObject> result = new ArrayList<>(input
.stream()
.collect(Collectors.toMap(
MyObject::getKey, //
mo -> new MyCreatedObject(
mo.getKey(),
new ArrayList<>(Arrays.asList(mo.getValue1())),
new ArrayList<>(Arrays.asList(mo.getValue2()))
),
(co1, co2) -> { // merge inner lists in MyCreatedObject
co1.getValue1List().addAll(co2.getValue1List());
co1.getValue2List().addAll(co2.getValue2List());
return co1;
}
//, LinkedHashMap::new // optional supplier to keep insertion order
))
.values()
);