Java 8By Thread Grouping: Value Attribute Summation

I have a simple Foo class:

class Foo {
   String type; 
   Integer quantity;
   String code;
   //...
}

and a list of objects of this type:

{ type=11, quantity=1, code=A },
{ type=11, quantity=2, code=A },
{ type=11, quantity=1, code=B },
{ type=11, quantity=3, code=C },
{ type=12, quantity=2, code=A },
{ type=12, quantity=1, code=B },
{ type=11, quantity=1, code=B },
{ type=13, quantity=1, code=C },
{ type=13, quantity=3, code=C }

I need to group by type first, and I can do this:

Map<String, List<Foo>> typeGroups = mylist.stream().collect(Collectors.groupingBy(Foo::getType));

The next step will convert the value Mapto List<Foo>as follows:

{ type=11, quantity=3, code=A },
{ type=11, quantity=2, code=B },
{ type=11, quantity=3, code=C },
{ type=12, quantity=2, code=A },
{ type=12, quantity=1, code=B },
{ type=13, quantity=4, code=C }

In SQL, I will have a query like this:

SELECT type, code, SUM(quantity) FROM Foo GROUP BY type, code

Let me explain in plain English.

I need to get a list of backgrounds. Each one code must be unique among its group, and the quantity must be the total amount of Foos having the same code among its group.

I tried to do this using groupingBy()c summingInt(), but not getting the desired result.

+4
source share
3

groupingBy, , type code. , , . ( , , , , Tuple).

Map<List<String>, Integer>, , . -: Foo, type - , quantity - , code - .

Map<List<String>, Integer> map = 
    myList.stream()
          .collect(Collectors.groupingBy(
             f -> Arrays.asList(f.getType(), f.getCode()),
             Collectors.summingInt(Foo::getQuantity)
          ));

List<Foo> result = 
    map.entrySet()
       .stream()
       .map(e -> new Foo(e.getKey().get(0), e.getValue(), e.getKey().get(1)))
       .collect(Collectors.toList());

, 2 . Stream, , . , . , API Stream . , StreamEx, .

- , Foo. : pairing(c1, c2, finisher), .

, . Map.values() Collection, ArrayList, .

List<Foo> result = new ArrayList<>(
    myList.stream()
          .collect(Collectors.groupingBy(
              f -> Arrays.<String>asList(f.getType(), f.getCode()),
              MoreCollectors.pairing(
                 Collectors.collectingAndThen(MoreCollectors.first(), Optional::get),
                 Collectors.summingInt(Foo::getQuantity),
                 (f, s) -> new Foo(f.getType(), s, f.getCode())
              )
          )).values());
+3

, ,

public class Foo {
    private String type;
    private int quantity;
    private String code;

    public Foo(String type, int quantity, String code) {
        this.type = type;
        this.code = code;
        this.quantity = quantity;
    }

    public String getType() {return type;}
    public int getQuantity() {return quantity;}
    public String getCode() {return code;}
}

List<Foo> foos = new ArrayList<>(); foos.add(new Foo("11", 1, "A")); foos.add(new Foo("11", 2, "A")); foos.add(new Foo("11", 1, "B")); foos.add(new Foo("11", 3, "C")); foos.add(new Foo("12", 2, "A")); foos.add(new Foo("12", 1, "B")); foos.add(new Foo("11", 1, "B")); foos.add(new Foo("13", 1, "C")); foos.add(new Foo("13", 3, "C"));

    foos.stream().collect(
                    toMap(
                            f -> f.getType() + f.getCode(),
                            Function.identity(),
                            (s, a) -> new Foo(
                                        s.getType(), 
                                        s.getQuantity() + a.getQuantity(),
                                        s.getCode()))
                          )
                    .values();        

Foo[type='12'|quantity=2|code='A'] 
Foo[type='13'|quantity=4|code='C'] 
Foo[type='12'|quantity=1|code='B'] 
Foo[type='11'|quantity=3|code='A'] 
Foo[type='11'|quantity=2|code='B'] 
Foo[type='11'|quantity=3|code='C']                       
+1

With rxjava help: groupBy + flatMap + reduce

    Observable.from(()->fooList.stream().iterator())
    .groupBy(f->Arrays.asList(f.type,f.code))
    .flatMap((Observable<Foo> o)->o
            .reduce((a,b)->new Foo(a.type,a.code,a.quantity+b.quantity))
    )
    .forEach((Foo o) ->
        System.out.println("type:" + o.type + " code:" + o.code +" qty:"+ o.quantity)
    )  ;
0
source

Source: https://habr.com/ru/post/1625869/


All Articles