How to transfer list A, B to tuple map card with guava

I apologize if this question is a duplicate, the search was difficult because I was not sure of the correct name of what I was trying to accomplish. The simplest explanation would be

List<A>, List<B> into Map<Key, Tuple<A,B>> where A.Key matched B.Key

To clarify: I have a list of objects A and object B that share the key. I would then like to map these two lists to a map, where the key matches the key map, and a tuple A, B.

I played with many ideas on how to do this in my head, but most of them end up feeling that I used the library incorrectly (e.g. Maps.uniqueIndex and Iterables.transform). Can someone point me in the right direction?

+5
source share
3 answers

Guava ( ..). ( , Java .) , , Multimap:

List<A> as = Lists.newArrayList(new A(1, "a"), new A(3, "c"), new A(2, "b"));
List<B> bs = Lists.newArrayList(new B(1, 2), new B(3, 6), new B(5, 10));

Function<WithKey, Object> toKey = new Function<WithKey, Object>() {
    @Override public Object apply(WithKey input) { return input.key(); }
};
ImmutableListMultimap<Object, AbstractWithKey> index = 
    Multimaps.index(Iterables.concat(as, bs), toKey);

Multimap<Object, WithKey> m = ArrayListMultimap.create();
for (WithKey w : Iterables.concat(as, bs)) m.put(w.key(), w);

( ), , A B. ( , Iterables.filter.)

- . HashMultimap, . , (. Multimaps.newSetMultimap(a > , > factory). Constraints.constrainedSet(Set set, )). , .

A B:

interface WithKey {
    Object key();
}
abstract class AbstractWithKey implements WithKey {
    Object key;
    Object v;
    @Override public Object key() { return key; }
    @Override public String toString() { 
        return MoreObjects.toStringHelper(this).add("k", key).add("v", v).toString(); 
    }
}
class A extends AbstractWithKey {
    public A(int i, String v) { 
        key = i;
        this.v = v;
    } 
}
class B extends AbstractWithKey {
    public B(int i, int v) { 
        key = i;
        this.v = v;
    }
}

:

{1 = [A {k = 1, v = a}, B {k = 1, v = 2}], 2 = [A {k = 2, v = b}], 3 = [A { k = 3, v = c}, B (k = 3, v = 6}], 5 = [B {k = 5, v = 10}]}

Update:

, Multimap.

Multimap<Object, WithKey> m = ArrayListMultimap.create(); 
for (WithKey w : Iterables.concat(as, bs)) m.put(w.key(), w);

Function<Collection<WithKey>, Tuple> f = 
    new Function<Collection<WithKey>, Tuple>(){
    @Override public Tuple apply(Collection<WithKey> input) {
        Iterator<WithKey> iterator = input.iterator();
        return new Tuple(iterator.next(), iterator.next());
    } };
Map<Object, Tuple> result = Maps.transformValues(m.asMap(), f);

((a, b) - ):

{1=(A{k=1, v=a},B{k=1, v=2}), 3=(A{k=3, v=c},B{k=3, v=6})}
+6

, ? ( , A, ?)

, - :

Map<Key, A> aMap = Maps.uniqueIndex(theAs, aKeyFunction); // Guava!
Map<Key, B> bMap = Maps.uniqueIndex(theBs, bKeyFunction);

Map<Key, AWithMatchingB> joinedMap = Maps.newHashMap();
for(Map.Entry<Key, A> aEntry : aMap.entrySet()) {
  joinedMap.put(aEntry.getKey(), AWithMatchingB.match(
     aEntry.getValue(), bMap.get(aEntry.getKey())));
}

, aMap.keySet(). equals (bMap.keySet()), : , B , ..

+1

Sorting lists by key and converting two lists into tuples without much help from Guava is quite readable:

Comparator<WithKey>c = new Comparator<WithKey>(){
    @Override public int compare(WithKey o1, WithKey o2) {
        return o1.key().compareTo(o2.key());
    }
};
Collections.sort(as, c);
Collections.sort(bs, c);

Preconditions.checkArgument(as.size() == bs.size());

Iterator<A> aIt = as.iterator();
Iterator<B> bIt = bs.iterator();
Map<Integer, Tuple> ts = Maps.newHashMap();
while(aIt.hasNext()) {
    A a = aIt.next();
    B b = bIt.next();
    Preconditions.checkArgument(a.key().equals(b.key()));
    ts.put(a.key(), new Tuple(a, b));
}

Output ((a, b) is the tuple syntax):

{1=(A{k=1, v=a},B{k=1, v=2}), 3=(A{k=3, v=c},B{k=3, v=6})}

This can be implemented better if Guava supports zip similar to Python:

sa = [(1, "a"), (3, "c")]
sb = [(1, 2), (3, 6)]

sa.sort()
sb.sort()

vs = [(a[0], (a,b)) for (a, b) in zip(sa, sb)]
0
source

All Articles