I have a list of object Ob
defined as
class Ob {
private String type;
private List<String> attire;
// standard getter and setters
public Ob (String type){
this.type=type;
}
public Ob addAttrire(String att){
if(attire == null){
attire = new ArrayList<>();
}
attire.add(att);
return this;
}
}
I receive objects as
[{
"type" : "upper"
attires : [{"t1","t2"}]
},
{
"type" : "upper"
attires : ["t3","t4"]
},
{
"type" : "lower"
attires : ["l1","l2"]
}]
which I have to combine as
[{
"type" : "upper"
attires : ["t1","t2","t3","t4"]
},{
"type" : "lower"
attires : ["l1","l2"]
}]
How can I use stream to do that. Does reduce help? The stream one can use is
List<Ob> coll = new ArrayList<>();
coll.add(new Ob("a").addAttrire("1").addAttrire("2").addAttrire("3"));
coll.add(new Ob("a").addAttrire("1").addAttrire("2").addAttrire("3"));
coll.add(new Ob("a").addAttrire("1").addAttrire("2").addAttrire("3"));
coll.add(new Ob("b").addAttrire("1").addAttrire("2").addAttrire("3"));
coll.add(new Ob("b").addAttrire("1").addAttrire("2").addAttrire("3"));
coll.add(new Ob("b").addAttrire("1").addAttrire("2").addAttrire("3"));
Collection<Ob> values = coll.stream()
.collect(toMap(Ob::getType, Function.identity(), (o1, o2) -> {
o1.getAttire().addAll(o2.getAttire());
return o1;
})).values();
Updated the question with solution of Ruben. There is no requirement to remove duplicates, but it can be done using set in Ob for attire. The current solution worked flawlessly.
You could collect toMap with a merge function that merges the lists
Collection<Ob> values = coll.stream()
.collect(toMap(Ob::getType, Function.identity(), (o1, o2) -> {
o1.getAttire().addAll(o2.getAttire());
return o1;
})).values();
This solution uses the groupingBy
collector and then a separate step that creates a new Ob
which is the result of merging all the Ob
s that have the same type
.
I think Rubens solution has an advantage over this answer because it's a little shorter and simpler. I think this answer has an advantage because it doesn't modify the original Ob
s and hence is more in a functional style.
public static void testTrickyStreamSet() {
Stream<Ob> s = Stream.of(
new Ob("a", "1", "2"),
new Ob("b", "1", "4"),
new Ob("a", "1", "3"),
new Ob("b", "1", "5"));
List<Ob> os = s.collect(groupingBy(o -> o.type))
.entrySet().stream()
.map(e -> new Ob(e.getKey(),
e.getValue().stream().flatMap(o -> o.attire.stream()).collect(toList())))
.collect(toList());
// Prints [<Ob type=a, attire=[1, 2, 3]>, <Ob type=b, attire=[1, 4, 5]>]
System.out.println(os);
}
public static class Ob {
public String type;
public List<String> attire;
public Ob(String type, String... attire) {
this.type = type;
this.attire = Arrays.asList(attire);
}
public Ob(String type, List<String> attire) {
this.type = type;
this.attire = new ArrayList<>(attire);
}
@Override
public String toString() {
return "<Ob type=" + type + ", attire=" + attire + ">";
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With