开发者

Intersect differently typed Collections

I have Collection<A> ca and Collection<B> cb, A and B sharing no common interface but each having a String property called something. I need to filter ca and retain only those elements which have a "correspondi开发者_运维技巧ng" value in cb.

Unfortunately, creating a common interface for A and B as per this question/answer is not an option.

I'm currently doing

Iterator<A> it = ca.iterator();
while ( it.hasNext() ) {
    A a = it.next();
    if ( !cb.contains(new B(a.getSomething(), ... <known stuff>) )
        it.remove;
}

exploiting the fact that I know what B.equals does. Is there anything I can do to improve this, performance- and/or resource-wise?


Could you put the As and Bs into Maps, keyed by String? Then you could just use Collection.retainAll() a couple of times:

Map<String, A> as = new HashMap<String, A>;
for (A a: ca) as.put(a.getSomething(), a);
Map<String, B> bs = new HashMap<String, B>;
for (B b: cb) bs.put(b.getSomething(), b);
as.keySet().retainAll(bs.keySet());
ca.retainAll(as.values());

Bit mad, but there you go.

bs could be a Set<String> rather than a Map, but i like the symmetry.


Can you thought about creating new wrapper objects?

interface Holder {
    Object getThing(); //or a primative

class HolderA implements Holder {
    private A a;

    public HolderA(A _a) {
        a = _a;
    }

    public Object getThing() {
        return a.getSomething();
    }
}

class HolderB implements Holder {
    private B b;

    public HolderB(B _b) {
        b = _b;
    }

    public Object getThing() {
        return b.getSomething();
    }
}

I think you should be able to compare those two objects.


You could use the Guava Collections2 class to transform and filter as follows:

Collection<A> as = ...;
Collection<B> bs = ...;

final Collection<String> b_somethings = 
    Collections2.transform(
        bs, 
        new Function<B, String>() {
            public String apply(B input) {
                return input.getSomething();
            }   
        });

Collection<A> filtered_as = 
    Collections2.filter(
        as, 
        new Predicate<A>() {
            public boolean apply(A input) {
                return b_somethings.contains(input.getSomething());
            }
        });
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜