Home > OS >  Iterate a list of query results in Java and create objects based on a key value
Iterate a list of query results in Java and create objects based on a key value

Time:12-02

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()));

Ideone Demo

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));

Ideone Demo 2

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()
);
  • Related