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());
}
});
精彩评论