3

I have map Map<Nominal, Integer> with objects and their counts:

a -> 3
b -> 1
c -> 2

And I need to get such a List<Nominal> from it:

a
a
a
b
c
c

How can I do this using the Stream API?

M. Justin
23.4k12 gold badges134 silver badges168 bronze badges
asked Aug 23, 2021 at 20:33
5
  • What is Nominal? Commented Aug 23, 2021 at 20:37
  • 1
    @GiorgiTsiklauri It’s not necessary to know what Nominal is to answer the question. Commented Aug 23, 2021 at 20:40
  • Nominal - it is Enum Commented Aug 23, 2021 at 20:41
  • @Bohemian how would you understand what is the type of key then? Commented Aug 23, 2021 at 20:42
  • @GiorgiTsiklauri as per the question, the type of the key is Nominal. That’s all you need to know - see my answer. Commented Aug 23, 2021 at 20:43

3 Answers 3

8

We can use Collections::nCopies to achieve the desired result:

private static <T> List<T> transform(Map<? extends T, Integer> map) {
 return map.entrySet().stream()
 .map(entry -> Collections.nCopies(entry.getValue(), entry.getKey()))
 .flatMap(Collection::stream)
 .collect(Collectors.toList());
}

Ideone demo


Remark

In the demo, I changed the key-type of the Map from Nominal to Object since the definition of Nominal was not provided. Changing the key-type, however, does not influence the solution.

answered Aug 23, 2021 at 20:42
Sign up to request clarification or add additional context in comments.

1 Comment

If desired, the .map and .flatMap calls can be combined into a single .flatMap: map.entrySet().stream().flatMap(e -> Collections.nCopies(e.getValue(), e.getKey()).stream()).toList().
1

Stream the entries and use flatMap to generate multiple copies of each key based on the value.

List<Nominal> expanded = map.entrySet().stream()
 .flatMap(e -> generate(e::getKey).limit(e.getValue()))
 .collect(toList());
answered Aug 23, 2021 at 20:38

Comments

1

Less concise than some other solutions, but here's a solution using Stream.mapMulti, which was added in Java 16:

List<Nominal> list = map.entrySet().stream()
 .<Nominal>mapMulti((e, c) -> {
 for (int i = 0; i < e.getValue(); i++) {
 c.accept(e.getKey());
 }
 })
 .toList();

Javadoc

API Note:

This method is similar to flatMap in that it applies a one-to-many transformation to the elements of the stream and flattens the result elements into a new stream. This method is preferable to flatMap in the following circumstances:

  • When replacing each stream element with a small (possibly zero) number of elements. Using this method avoids the overhead of creating a new Stream instance for every group of result elements, as required by flatMap.
  • When it is easier to use an imperative approach for generating result elements than it is to return them in the form of a Stream.
answered Dec 6, 2024 at 21:31

Comments

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

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.