Home > Software design >  How to iterate over a Map to obtain a String of repeated Character Keys with Java 8
How to iterate over a Map to obtain a String of repeated Character Keys with Java 8

Time:05-20

I have a Map shown below:

Map<Character, Integer> map = new LinkedHashMap<Character, Integer>();
    map.put('c', 5);
    map.put('f', 2);
    map.put('r', 1);
    map.put('D', 3);

I need to obtain the output:

cccccffrDDD

I can do it in normal process, but I want to do it in Java 8. Can you share some hints how to achieve this?

CodePudding user response:

Is this what you need?

        Map<Character, Integer> map = new LinkedHashMap<Character, Integer>();
        map.put('c',5);
        map.put('f', 2);
        map.put('r', 1);
        map.put('D', 3);

        StringBuilder sb = new StringBuilder();
        map.forEach((k,v)->{
            sb.append(String.valueOf(k).repeat(v));
        });
        System.out.print(sb);

Notice that the repeat method is only avaliable above Java 11.

For Java 1.8 version

        StringBuilder sb = new StringBuilder();
        map.forEach((k,v)->{
            for(int i=0; i<v; i  ) {
                sb.append(k);
            }
        });
        System.out.print(sb);

CodePudding user response:

You can use forEach() and StringBuilder to compose.

StringBuilder sb = new StringBuilder(); 
  map.forEach((k,v) -> { 
  for (int i = 0; i < v; i  ) { 
    sb.append(k); 
  } 
}); 

CodePudding user response:

You can stream the entry set of the map and print the key with its value as factor using String.repeat(int count) (introduced in Java 11), maybe as follows:

public static void main(String[] args) {    
    Map<Character, Integer> map = new LinkedHashMap<Character, Integer>();
    map.put('c',5);
    map.put('f', 2);
    map.put('r', 1);
    map.put('D', 3);
    // stream the set of entries and repeat the (String version of the) key value-times
    map.entrySet().forEach(e -> System.out.print(e.getKey().toString().repeat(e.getValue())));
}

This prints

cccccffrDDD

CodePudding user response:

When you are using Java 8, which doesn’t have the String.repeat(…) method, you may use

String result = map.entrySet().stream()
   .map(e -> {
       char[] array = new char[e.getValue()];
       Arrays.fill(array, e.getKey());
       return CharBuffer.wrap(array);
   })
   .collect(Collectors.joining());

or use a custom collector:

String result = map.entrySet().stream()
    .collect(Collector.of(
        StringBuilder::new,
        (sb, e) -> { for(int i = e.getValue(); i > 0; i--) sb.append(e.getKey()); },
        StringBuilder::append,
        StringBuilder::toString));

CodePudding user response:

Here's a couple of ideas on how to approach this problem using Java 8 streams.

The overall idea:

  • create a stream of map entries;
  • generate a stream of single-letter strings based on each entry and merge them using built-in collector joining();
  • apply collect with collector joining() to obtain the final result.
String joinedLetters = map.entrySet().stream()
    .map(entry -> Stream.generate(() -> String.valueOf(entry.getKey()))
        .limit(entry.getValue())
        .collect(Collectors.joining()))
    .collect(Collectors.joining());

Another way of achieving this:

  • create a stream of entries;
  • create a lightweight list of Strings using Collections.nCopies();
  • turn each list into a String using static method String.join();
  • combine the strings together using collector joining().
String joinedLetters = map.entrySet().stream()
    .map(entry -> Collections.nCopies(entry.getValue(), String.valueOf(entry.getKey())))
    .map(list -> String.join("", list))
    .collect(Collectors.joining());

Use this link to play around with Online demo

CodePudding user response:

As mentioned above, you can build the string by using the lambda expression as follows.

StringBuilder output = new StringBuilder();
map.forEach((k, v) -> {
    for (int i = 0; i < v; i  ) {
        output.append(k);
    }
});

Or you can replace the standard with IntStreams.

StringBuilder output = new StringBuilder();
map.forEach((k, v) -> IntStream.range(0, v).forEach(i -> b.append(k)));
  • Related