Reputation: 140
We have object A type that contains an array of objects B type than contains an array of objects C type like in the example:
/* sample structure that ends with 4 instances of C with ids.100,200,100,200 */
private class A{
int id;
A(int id) {
this.id = id;
}
B[] b = new B[]{new B(10), new B(20) };
}
private class B{
int id;
B(int id) {
this.id = id;
}
C[] c = new C[]{new C(100), new C(200) };
}
private class C{
int id;
C(int id) {
this.id = id;
}
public String toString(){
return ""+id;
}
}
If we try to get all distinct c.id (100, 200) the first approach could be
HashSet<Integer> distinctIdsOfC = new HashSet<Integer>();
for (B bbb: a.b){
for (C ccc: bbb.c){
distinctIdsOfC.add(ccc.id);
}
}
(The result is 100, 200 as expected)
And my first attepmt with lambdas
List<C> a6 = Arrays.asList(a.b).stream().map(jaja -> Arrays.asList(jaja.c)).flatMap(List::stream).collect(Collectors.toList());
a6.stream().map(x->x.id).distinct().forEach(System.out::println);
(The result is again 100, 200 as expected)
And finally the question. Any better alternative lambda?
/* Complete source sample to test */
package test;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.stream.Collectors;
public class Test {
public static void main(String[] args) {
Test t = new Test();
t.haz();
}
private void haz() {
A a = new A(1);
HashSet<Integer> distinctIdsOfC = new HashSet<Integer>();
for (B bbb : a.b) {
for (C ccc : bbb.c) {
distinctIdsOfC.add(ccc.id);
}
}
System.out.println("with for-loop" + distinctIdsOfC.toString());
System.out.println("with lambda");
List<C> a6 = Arrays.asList(a.b).stream().map(jaja -> Arrays.asList(jaja.c)).flatMap(List::stream)
.collect(Collectors.toList());
a6.stream().map(x -> x.id).distinct().forEach(System.out::println);
}
private class A {
int id;
A(int id) {
this.id = id;
}
B[] b = new B[] { new B(10), new B(20) };
}
private class B {
int id;
B(int id) {
this.id = id;
}
C[] c = new C[] { new C(100), new C(200) };
}
private class C {
int id;
C(int id) {
this.id = id;
}
public String toString() {
return "" + id;
}
}
}
Upvotes: 3
Views: 1232
Reputation: 1740
Ok, I think we many options but:
1) Implementes equlas/hashCode in C class, and then:
Arrays.stream(a.b)
.map(s -> s.c)
.flatMap(Arrays::stream)
.distinct()
.forEach(System.out::println)
But, if You can't add hashCode/equals:
2) Create filter method (distinct by class field):
public static <T> Predicate<T> distinctByKey(Function<? super T, ?> keyExtractor) {
Map<Object,Boolean> seen = new ConcurrentHashMap<>();
return t -> seen.putIfAbsent(keyExtractor.apply(t), Boolean.TRUE) == null;
}
And then write lambdas like this:
Arrays.asList(a.b).stream()
.map(jaja -> Arrays.asList(jaja.c))
.flatMap(List::stream)
.filter(distinctByKey(s -> s.id))
.forEach(System.out::println);
Upvotes: 4
Reputation: 140
With all the valuable information in comments, the idea that we was looking for distinct id values, not distict objects and trying to get it simpler, ended with the lambda.
/* proposed lambda */
System.out.println("with lambda");
Set<Integer> a7 = Arrays.stream(a.b).flatMap(jaja-> Arrays.stream(jaja.c).map(jeje->jeje.id)).collect(Collectors.toSet());
System.out.println("with lambda set a7");
a7.stream().forEach(System.out::println);
That avoids intermediate non use List, avoids distinct and it's shorter and clear.
Upvotes: 0