Stream<Map.Entry<String, Long>> duplicates = notificationServiceOrderItemDto.getService()
.getServiceCharacteristics()
.stream()
.collect(
Collectors.groupingBy(
ServiceCharacteristicDto::getName, Collectors.counting()
)
)
.entrySet()
.stream()
.filter(e -> e.getValue() > 1);
Optional<String> dupName = duplicates.map(Map.Entry::getKey).findFirst();
works perfect. But I wold like to find duplicates not just with name but also name + value + key
That means if name + value + key is the same this is duplicate.
I am looking Collectors.groupingBy()
http://www.technicalkeeda.com/java-8-tutorials/java-8-stream-grouping
but I can not find correct solution
Following works for me:
public class Groupingby
{
static class Obj{
String name;
String value;
String key;
Obj(String name, String val, String key)
{
this.name = name;
this.value = val;
this.key = key;
}
}
public static void main(String[] args)
{
List<Obj> objects = new ArrayList<>();
objects.add(new Obj("A", "K", "Key1"));
objects.add(new Obj("A", "K", "Key1"));
objects.add(new Obj("A", "X", "Key1"));
objects.add(new Obj("A", "Y", "Key2"));
Map<List<String>, Long> collected = objects.stream().collect(Collectors.groupingBy(x -> Arrays.asList(x.name, x.value, x.key), Collectors.counting()));
System.out.println(collected);
}
}
// Output
// {[A, K, Key1]=2, [A, Y, Key2]=1, [A, X, Key1]=1}
Note that I am using list of attributes for grouping by, not string concatenation of attributes. This will work with non-string attributes as well.
If you are doing string concatenation, you may have some corner cases like attributes (A, BC, D) and (AB, C, D) will result in same string.
Instead of
.collect(Collectors.groupingBy(ServiceCharacteristicDto::getName, Collectors.counting()))
you can write
.collect(Collectors.groupingBy(s->s.getName()+'-'+s.getValue()+'-'+s.getKey(), Collectors.counting()))
You can replace ServiceCharacteristicDto::getName
with:
x -> x.getName() + x.getValue() + x.getKey()
Use a lambda instead of a method reference.
But also think of what findFirst would actually mean here... you are collecting to a HashMap that has no encounter order, streaming its entries and getting the first element - whatever that is. You do understand that this findFirst
can give different results on different input, right? Even re-shuffling the HashMap
could return you a different findFirst
result.
EDIT
to get away from possible un-intentional duplicates because of String concat, you could use:
x -> Arrays.asList(x.getName(), x.getValue(), x.getKey())
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