代码之家  ›  专栏  ›  技术社区  ›  Иван Волынчук

Java Guava过滤器两个不同类型的集合

  •  2
  • Иван Волынчук  · 技术社区  · 9 年前

    我有两个收藏:

    ArrayList<B> currentB = new ArrayList<B>();
    {
        currentB.add(new B(new A("1")));
        currentB.add(new B(new A("2")));
        currentB.add(new B(new A("7")));
        currentB.add(new B(new A("3")));
        currentB.add(new B(new A("4")));
    }
    ArrayList<A> newA = new ArrayList<A>();
    {
        newA.add(new A("1"));
        newA.add(new A("5"));
        newA.add(new A("2"));
        newA.add(new A("6"));
        newA.add(new A("7"));
        newA.add(new A("8"));
    
    }
    

    集合有以下类型:

    class A {
        private String id;
    
        public String getId() {
            return id;
        }
    
        public void setId(String id) {
            this.id = id;
        }
    
        @Override
        public boolean equals(Object o) {
            if (this == o) return true;
            if (o == null || getClass() != o.getClass()) return false;
    
            A nodeRef = (A) o;
    
            return !(id != null ? !id.equals(nodeRef.id) : nodeRef.id != null);
    
        }
    
        public A() {
        }
    
        public A(String id) {
            this.id = id;
        }
    
        @Override
        public String toString() {
            return "NodeRef{" +
                    "id='" + id + '\'' +
                    '}';
        }
    }
    
    class B {
        private A a;
    
        public A a() {
            return a;
        }
    
        public A getA() {
            return a;
        }
    
        public void setA(A a) {
            this.a = a;
        }
    
        @Override
        public String toString() {
            return "B{" +
                    "a=" + a +
                    '}';
        }
    
        public B(A a) {
            this.a = a;
        }
    
        public B() {
        }
    }
    

    我想创建(最好的结果是修改newA和currentB)两个列表:

    • 第一个应该有对象,而不是在另一个中表示
      一个(在示例情况下为a(3)、a(4));
    • 第二个逻辑相同但反之亦然:(a(5)、a(6)、, a(8))。

    我可以用番石榴做,但需要制作3个系列:

    Function<B, A> BtoA = new Function<B, A>() {
        public A apply(final B b) {
            return b.getA();
        }
    };
    Collection<A> currentA = Collections2.transform(currentB, BtoA);
    
    java.util.Collection<A> idToDelete = Collections2.filter(currentA, Predicates.not(Predicates.in(newA)));
    java.util.Collection<A> idToAdd = Collections2.filter(newA, Predicates.not(Predicates.in(currentA)));
    
    System.out.println("Old B" + idToDelete);
    System.out.println("New A" + idToAdd);
    

    有没有办法摆脱Collection。转变甚至是最好的方式?

    1 回复  |  直到 9 年前
        1
  •  4
  •   Dzmitry Paulenka    9 年前

    它与java 8流API一起看起来很不错:

    java.util.Collection<String> idToDelete =
            currentB.stream() //get the stream
            .filter(b -> !newA.contains(b.getA())) // filter those b, whose A is in newA
            .map(b -> b.getA().id) // map transform to get just an Id (you can use just getA() here)
            .collect(Collectors.toList()); // finally transform back to list
    
    java.util.Collection<String> idToAdd =
            newA.stream() // again get stream
            .filter(
                    // this is a little bit fancy...
                    // only leave those A, for which currentB doesn't contain element, that has getA() equals to that A
                    a -> currentB.stream().noneMatch(
                            b -> b.getA().equals(a)
                    )
            )
            .map(a -> a.id) // again get id
            .collect(Collectors.toList()); // transform to list
    

    [编辑:]

    如果你查看番石榴的源代码,你会发现 transform 只需用一个转换函数包装现有的一个。因此,番石榴基本上与java8流一样工作。所以你可以像以前一样使用变换。如果绝对不想这样做,这是番石榴的完整例子:

    Function<B, A> BtoA = new Function<B, A>() {
        public A apply(final B b) {
            return b.getA();
        }
    };
    Function<A, String> aToId = new Function<A, String>() {
        public String apply(final A a) {
            return a.getId();
        }
    };
    
    java.util.Collection<B> bToDelete = Collections2.filter(currentB, Predicates.compose(Predicates.not(Predicates.in(newA)), BtoA));
    
    //without transform, looks ugly
    java.util.Collection<A> aToAdd = Collections2.filter(newA, new Predicate<A>() {
        @Override
        public boolean apply(final A a) {
            return !Iterables.any(currentB, new Predicate<B>() {
                @Override
                public boolean apply(B b) {
                    return b.getA().equals(a);
                }
            });
        }
    });
    // this is essentially the same, you can safely use transform
    //java.util.Collection<A> aToAdd = Collections2.filter(newA, Predicates.not(Predicates.in(Collections2.transform(currentB, BtoA))));
    
    java.util.Collection<String> idToDelete = Collections2.transform(bToDelete, Functions.compose(aToId, BtoA));
    java.util.Collection<String> idToAdd = Collections2.transform(aToAdd, aToId);
    
    System.out.println("Old B: " + idToDelete);
    System.out.println("New A: " + idToAdd);