5

I am searching for an elegant equivalent of this piece of code using Java 8's streams:

Collection<X> xs = ...;
Map<B, A> map = new SomeMap<>();

for (X x : xs) {
    A a = x.getA();
    Collection<B> bs = x.getBs();

    for (B b : bs)
        map.put(b, a);
}

That one is a bit too tricky for me as I can’t think of a combination using flatMap and Collectors.toMap which would implement the desired functionality.

Compilable example:

import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;

public class Application {

    public static class A {}

    public static class B {}

    public static class X {
        private A a;
        private Collection<B> bs;

        public X(A a, Collection<B> bs) {
            this.a = a;
            this.bs = bs;
        }

        public A getA() {
            return a;
        }

        public Collection<B> getBs() {
            return bs;
        }
    }

    public static void main(String[] args) {
        X x1 = new X(new A(), Arrays.asList(new B(), new B()));
        X x2 = new X(new A(), Arrays.asList(new B()));

        Collection<X> xs = Arrays.asList(x1, x2);

        Map<B, A> map = new HashMap<>();

        for (X x : xs) {
            A a = x.getA();
            Collection<B> bs = x.getBs();

            for (B b : bs)
                map.put(b, a);
        }
    }

}
11
  • 1
    Are you sure it is xs.getA()? Commented Nov 10, 2014 at 16:44
  • 2
    you declare a Map<A, B> but you use map.put(b, a) - which did you mean? Commented Nov 10, 2014 at 16:48
  • Oh, yeah. It's Map<B, A>. Commented Nov 10, 2014 at 16:57
  • You should post a simple but complete and compilable example instead of pseudo code. Commented Nov 10, 2014 at 17:02
  • 1
    for( ... : xs) { ... = xs.getA(); ... = xs.getBs(); } It's not just pseudocode, it actually doesn't make sense. I stared at it for a good minute before I realized that it was meaningless. Commented Nov 10, 2014 at 19:06

1 Answer 1

5

As you thought you can do it with a mixture of flatMap and toMap:

Map<B, A> map = xs.stream()
                  .flatMap(x -> x.getBs().stream()
                                 .map(b -> new SimpleEntry<> (b, x.getA())))
                  .collect(toMap(Entry::getKey, Entry::getValue));

Note that this code differs from your original if there are duplicate Bs: your code will keep overwriting the corresponding value whereas this code will throw an exception.

Sign up to request clarification or add additional context in comments.

3 Comments

The only way I get this to work is by casting the inner stream to Stream<SimpleEntry<B, A>>. Otherwise I would get a type error at collect.
With your example the code I've given works fine with no cast involved. You haven't forgotten the <> in new SimpleEntry<> (...) by any chance?
Might be the Java version. I tried it on a different machine where the same code worked while it didn't on the other machine.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.