0

I have a list of Services, for sample:

public class Service {
   private long id;
   private String name;
   private BigDecimal value;
}

List<Service> services;

my user can add a lot of services, but I need to show a grouped services, If my user add 3 times the service with id 1, I need to show only one time but with a properties quantity

* EDIT *

I have this class:

public class ServicoCalculado implements Serializable{
    private Long idServico;
    private String nmServico;
    private BigDecimal vlBase = BigDecimal.ZERO;
    private BigDecimal vlTotal = BigDecimal.ZERO;
  // getters e setters
}

so my User can add a lot of services:

List< ServicoCalculado> services = new ArrayList<>();
services.add(new ServicoCalculado(1, 'name 1', 1,2);
services.add(new ServicoCalculado(1, 'name 1', 1,2);
services.add(new ServicoCalculado(1, 'name 1', 1,2);
services.add(new ServicoCalculado(2, 'name 2', 2,3);
services.add(new ServicoCalculado(3, 'name 3', 2,4);

So then I have a class to show in a grid:

public class ServicosVO {
    private Long idServico;
    private String nmServico;
    private BigDecimal vlBase;
    private BigDecimal total;
    private int qtd;
}

So I need to transform the first List in a List of second

This is the output

idServico || nmServico || vlBase || total || qtd

1       ||  name 1    ||     3   ||  6    ||  3 
2       ||  name 2    ||     2   ||  3    ||  1 
3       ||  name 3    ||     2   ||  4    ||  1 
Fabio Ebner
  • 2,613
  • 16
  • 50
  • 77
  • 2
    Possible duplicate of [Group by counting in Java 8 stream API](https://stackoverflow.com/questions/25441088/group-by-counting-in-java-8-stream-api) – Malte Hartwig Jul 26 '18 at 14:39
  • For me, it is still unclear what the expected result is. Could you explain further? – Glains Jul 26 '18 at 14:42
  • problem is... which one will you show? they have the same ID, but what if they have different names> Or different values? I'm voting to close this as it is unclear – Eugene Jul 26 '18 at 14:52

4 Answers4

1

You can use Map instead of a list and set whatever you want to make unique as keys.

Onur Arı
  • 502
  • 1
  • 4
  • 16
1

here's another variant to getting a map of ids and a count of their occurrences:

services.stream()
        .collect(Collectors.toMap(Service::getId, e -> 1, Math::addExact));

if you actually want to apply some merging logic in the case of a key collision and get back, as a result, a collection of services then use the toMap collector as follows:

Collection<Service> resultSet = services.stream()
        .collect(Collectors.toMap(Service::getId, 
                       e -> new ArrayList<>(Collections.singletonList(e)),
                       (l, r){ /* merging logic here */}).values();
Ousmane D.
  • 54,915
  • 8
  • 91
  • 126
  • You did some unnecessary acrobatics in the first code segment, the second one was in place (good). The first code segment is simply replaceable by `services.stream().collect(Collectors.groupingBy(Service::getId, Collectors.counting()))`. – marsouf Jul 26 '18 at 15:37
  • @marsouf I didn’t use groupingBy/counting as there is already an answer with that so I decided to take something else out my sleeves :-). Anyhow, after reading the post another few times I just think the OP might be after my second solution. I am not sure what you mean by unnecessary acrobatics? – Ousmane D. Jul 26 '18 at 15:47
  • @marsouf Right, might of just got what you mean and I think I’ve already answered that. That said, even though groupingBy with the counting downstream collector is more readable there is definitely more ways to accomplish the task in a compact and concise way hence my solution using toMap collector. – Ousmane D. Jul 26 '18 at 15:55
  • 1
    Agreed, hence my upvote :) – marsouf Jul 26 '18 at 15:57
0

If I understood you correctly:

 services.stream()
         .collect(Collectors.groupingBy(
              Service::getId, 
              Collectors.counting()))
Eugene
  • 117,005
  • 15
  • 201
  • 306
0

You could create a subclass of Service:

public class MultipleService extends Service{
    private long quantity;

    public MultipleService(Service service, long quantity){
        // assuming parent has a all arg constructor
        this(service.id, service.name, service.value);
        this.quantity = quantity;
    }
}

And then reduce it into that:

List<MultipleService> list = services.stream()
    .collect(Collectors.groupingBy(Function.identity(), Collectors.counting()))
    .entrySet().stream()
    .map(e -> new MultipleService(e.getKey(), e.getValue()))
    .collect(Collectors.toList());

This answers assumes that equals and hashcode are properly overriden for Service

Lino
  • 19,604
  • 6
  • 47
  • 65