Java 更好的lambda在对象层次结构上获得不同的值

Java 更好的lambda在对象层次结构上获得不同的值,java,lambda,Java,Lambda,我们的对象A类型包含对象B类型的数组,而不是包含对象C类型的数组,如示例中所示: /* 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

我们的对象A类型包含对象B类型的数组,而不是包含对象C类型的数组,如示例中所示:

/* 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;
        }

    }
如果我们试图获得所有不同的c.id(100200),第一种方法可能是

HashSet<Integer> distinctIdsOfC = new HashSet<Integer>();
for (B bbb: a.b){
    for (C ccc: bbb.c){
        distinctIdsOfC.add(ccc.id);
    }
}
HashSet-differenticsofc=new-HashSet();
(B bbb:a.B){
适用于(ccc:bbb.C){
区别OFC.add(ccc.id);
}
}
(结果是预期的100200)

我的第一次尝试是和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);
lista6=Arrays.asList(a.b.stream().map(jajaja->Arrays.asList(jajaja.c)).flatMap(List::stream).collect(collector.toList());
a6.stream().map(x->x.id).distinct().forEach(System.out::println);
(结果还是预期的100200)

最后是问题有更好的兰姆达替代品吗?

/*要测试的完整源示例*/
包装试验;
导入java.util.array;
导入java.util.HashSet;
导入java.util.List;
导入java.util.stream.collector;
公开课考试{
公共静态void main(字符串[]args){
测试t=新测试();
t、 haz();
}
私有无效haz(){
A=新的A(1);
HashSet-differentidsofc=新的HashSet();
(B bbb:a.B){
适用于(ccc:bbb.C){
区别OFC.add(ccc.id);
}
}
System.out.println(“with for loop”+distributedsofc.toString());
System.out.println(“带lambda”);
lista6=Arrays.asList(a.b.stream().map(jaja->Arrays.asList(jajaja.c)).flatMap(List::stream)
.collect(Collectors.toList());
a6.stream().map(x->x.id).distinct().forEach(System.out::println);
}
私人甲级{
int-id;
A(整数id){
this.id=id;
}
B[]B=新的B[]{新的B(10),新的B(20)};
}
私人乙级{
int-id;
B(内部id){
this.id=id;
}
C[]C=newc[]{newc(100),newc(200)};
}
私人C类{
int-id;
C(内部id){
this.id=id;
}
公共字符串toString(){
返回“”+id;
}
}
}

好的,我想我们有很多选择,但是:

1) 在C类中实现Equals/hashCode,然后:

        Arrays.stream(a.b)
            .map(s -> s.c)
            .flatMap(Arrays::stream)
            .distinct()
            .forEach(System.out::println)
但是,如果不能添加hashCode/equals:

2) 创建筛选器方法(按类字段区分):


有了评论中所有有价值的信息,我们寻找的是不同的id值,而不是不同的对象,并试图让它更简单, 以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);
/*提议的lambda*/
System.out.println(“带lambda”);
Set a7=Arrays.stream(a.b).flatMap(jaja->Arrays.stream(jajaja.c.map(jeje->jejeje.id)).collect(Collectors.toSet());
System.out.println(“带有lambda集合a7”);
a7.stream().forEach(System.out::println);

这样就避免了中间的非使用列表,避免了使用distinct,而且它更短、更清晰。

Arrays.stream(b.c))。但您真正应该做的是停止使用数组。使用列表代替。不幸的是,这不在我的手中。对象结构是强制的。哦,当然,使用
collect(Collectors.toSet())
。为什么要查看列表?不确定为什么要将流表达式分成两条语句。为什么不在
flatMap
之后继续,并收集到一个集合或在结果上使用distinct?我使用了两个语句,因为这是我的第一个“真实”lambda,不包括教程、书籍或研究。没有真正的原因,只要我们处理数组,就应该使用
arrays.stream
stream.of
而不是
arrays.asList().stream()
。除了
map(asList)
之外,您还可以直接调用
flatMap
flatMap(jajaja->Arrays.stream(jajaja.c))
。这样你就不会创建一个你根本不需要的列表了。对,下一个更好的解决方案是
Arrays.asList(a.b).stream().map(s->s.c).map(Arrays::stream).distinct()/…code…/
谢谢@roland小心
map(Arrays::stream)
。。。应该是:
Arrays.stream(a.b).map(s->s.c).flatMap(Arrays::stream).distinct().forEach(System.out::println)好的,所以请这样内联:
数组.stream(a.b).map(s->s.c).flatMap(Arrays::stream).map(s->s.id).distinct().forEach(System.out::println)
。我的答案和您的解决方案之间的区别是只添加一个.map(函数),然后您就有了简单的代码,并且您有与所有对象C类不同的ID。当您只想执行
forEach(…)
时,无需使用
stream()
。您只需执行
a7.forEach(System.out::println)
但正如Mateusz所说,您可以在前面的流操作中执行
forEach
,而不必收集到
集合中。
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;
}
        Arrays.asList(a.b).stream()
            .map(jaja -> Arrays.asList(jaja.c))
            .flatMap(List::stream)
            .filter(distinctByKey(s -> s.id))
            .forEach(System.out::println);
    /* 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);