【问题标题】:Java Guava filter two collection with different typeJava Guava过滤两个不同类型的集合
【发布时间】:2016-05-09 04:02:40
【问题描述】:

我有两个收藏:

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.transform 甚至是最好的方法?

【问题讨论】:

    标签: java collections filter guava


    【解决方案1】:

    使用 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
    

    [编辑:]

    如果您查看 guava 的源代码,您会看到,transform 只是用一个转换函数包装了您现有的源代码。所以番石榴基本上就像java 8流一样工作。所以你实际上可以像以前一样使用变换。如果绝对不想这样做,这是番石榴的完整示例:

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

    【讨论】:

    • 它工作得更快 - 谢谢。但我有一个限制——我只能使用 java7。有没有办法不使用java8?
    • 我已经编辑了答案,添加了番石榴的工作示例。
    • 感谢您的解释。所以在 Guava 中没有另一种('beaty')方式(只需调用一个带有所有参数的函数)?
    • 我不这么认为。 Guava 基本上实现了对集合的常用功能操作。 filtermapanynone 等。我可以想象一些 mapFilterfilterMap mtehods,但它们通常不会单独实现,因为它们并没有真正推动作曲filtermap 随心所欲。
    • 感谢您的解释。
    猜你喜欢
    • 2014-03-05
    • 1970-01-01
    • 2018-03-02
    • 2016-07-26
    • 1970-01-01
    • 2013-10-10
    • 2011-01-14
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多