3

I have a List<Computer>. Every Computer has a list of CPU and a hostname. So,suppose I have:

List<Computer> computers

I can call

List<CPU> CPUs = computer.getCPUs();

and I can call

String hostname = computer.getHostName();

What I want to do is, using Streams, obtain a Map that contains as key the CPU and as String the hostname. Same CPU inside the same Computers will replicate the hostname.

How can I do that?

Pre Java8 code would be this:

public Map<CPU, String> getMapping(List<Computer> computers) {
    Map<CPU, String> result = new HashMap<>();
    for (Computer computer : computers) {
        for (CPU cpu : computer.getCPUs()) {
            result.put(cpu, computer.getHostname());
        }
    }

    return result;
}
4
  • 3
    What is the relationship between computer and computers. If you want your question to survive add pre-Java 8 code that accomplishes your task. Commented Jan 13, 2017 at 17:16
  • thanks, I added pre Java8 code Commented Jan 13, 2017 at 18:03
  • 1
    I think there's no streams & lambdas solution better than the one you already have Commented Jan 13, 2017 at 18:27
  • What happens If the same CPU links to more than two Hostnames? Commented Jan 13, 2017 at 19:49

3 Answers 3

1

If your CPU class has a back-reference to it's Computer instance, then you can do this easily. First stream over all the computers, and flat-map with getCPUs, this will give you a Stream<CPU> of all CPUs. Then you can use Collectors.toMap to collect into a Map<CPU, String> using Function.identity for the key and a lambda extracting first the Computer and then the hostname from the CPU for the value. In code:

computers.stream()
    .flatMap(computer -> computer.getCPUs().stream())
    .collect(Collectors.toMap(Function.identity(), cpu -> cpu.getComputer().getHostname()));
Sign up to request clarification or add additional context in comments.

2 Comments

What leads you to the assumption that there is a cpu.getComputer() method?
As I explained in the first sentence, I assumed this because it is a reasonable assumption and necessary for this to be solvable cleanly with the Stream API. If such a method does not exist, the stream pipeline would get more inefficient, because I don't think you could do it without an intermediate collect step.
1

You could do it by implementing your own Collector in order to assign the same value to all the CPUs of the same computer:

Map<CPU, String> cpus = computers.stream().collect(
    Collector.of(
        HashMap::new,
        // Put each cpu of the same computer using the computer's hostname as value
        (map, computer) -> computer.getCPUs().stream().forEach(
            cpu -> map.put(cpu, computer.getHostName())
        ),
        (map1, map2) -> { map1.putAll(map2); return map1; }
    )
);

This is basically the equivalent of what you currently do using the Stream API, the only difference is the fact that you could parallelize it by simply using a parallel stream instead of a normal stream, but in this particular case as the tasks are quite small, it would probably not help much in term of performances such that using the Stream API in this case could be considered as a little bit abusive.

Comments

1

You can do it using an intermediate Entry to hold the CPU and hostname together:

Map<CPU, String> map = computers.stream()
        .flatMap(c -> c.getCPUs().stream().map(cpu -> new AbstractMap.SimpleEntry<>(cpu, c.getHostName())))
        .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));

Comments

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.