更好的lambda来获取对象层次结构上的不同值

时间:2017-01-16 07:45:22

标签: java lambda

我们有一个对象一个类型,它包含一个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 (100,200),第一种方法可能是

HashSet<Integer> distinctIdsOfC = new HashSet<Integer>();
for (B bbb: a.b){
    for (C ccc: bbb.c){
        distinctIdsOfC.add(ccc.id);
    }
}

(结果是预期的100,200)

我第一次与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);

(结果再次是100,200,如预期的那样)

最后问题。 任何更好的替代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;
        }
    }

}

2 个答案:

答案 0 :(得分:4)

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

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

$('.selectpicker').selectpicker({
  style: 'btn-info',
  size: 4
});

但是,如果你不能添加hashCode / equals:

2)创建过滤方法(由类字段区分):

        Arrays.stream(a.b)
            .map(s -> s.c)
            .flatMap(Arrays::stream)
            .distinct()
            .forEach(System.out::println)

然后写下这样的lambdas:

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

答案 1 :(得分:0)

在评论中包含所有有价值的信息,我们一直在寻找不同的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);

这避免了中间非使用List,避免明显的,并且它更短更清晰。