Home > Software engineering >  Retrieve word(s) from characters using map
Retrieve word(s) from characters using map

Time:11-12

I am trying to understand Collections and Stream.

I have split the sentence below and kept the position of each letter (I ignored space/blank): "Hello Word!"

private static final String text = "Hello Word!";
static Map<String, List<Integer>> charsIndex = new HashMap<>();
static void charsIndex() {

        List<Character> charsList = text
                .chars()
                .mapToObj(e -> (char) e)
                .toList();
        System.out.println(charsList);

        int  position = 0;
        for (Character c : charsList) {
            if(!c.toString().isBlank()){
                charsIndex.computeIfAbsent(c.toString(),
                        addCharPosition -> new ArrayList<>()).add(position);
            }
            position  = 1;
        }

        System.out.println(charsIndex);
}

Results:

[H, e, l, l, o, , W, o, r, d, !] (charsList)

{!=[10], r=[8], d=[9], e=[1], W=[6], H=[0], l=[2, 3], o=[4, 7]} (charsIndex)

How can I sort the characters and rebuild my word along with the blank?

I try this way:

static void charsToString(){

  charsIndex.forEach((character, l) -> l.forEach(position -> {

  }));
}

CodePudding user response:

You can restore the original string based on the map of indices in the following steps:

  • Sort the characters according to their positions. Because each entry in the map associates a character with multiple indices, for that you would need to define an auxiliary type, holding a reference to a single-char string and distinct position of this character. Let's call it CharPosition

  • Generate a list of CharPosition (which is sorted).

  • To restore the white spaces, we can define an array, having a length of the highest index 1. Then populate this array with the contents of the CharPosition list.

  • Finally, create a stream over the array elements, replace all null values with a white space and generate the resulting String using Collector joining().

For the purpose of conciseness, I'll use a Java 16 record to implement CharPosition:

public record CharPosition(String ch, int pos) {}

That's how the logic described above can be implemented:

static void charsToString() {
    
    List<CharPosition> charPositions = charsIndex.entrySet().stream()
        .flatMap(entry -> entry.getValue().stream()
            .map(pos -> new CharPosition(entry.getKey(), pos))
        )
        .sorted(Comparator.comparingInt(CharPosition::pos))
        .toList();
    
    int wordLen = charPositions.get(charPositions.size() - 1).pos()   1;
    
    String[] word = new String[wordLen];
    
    charPositions.forEach(c -> word[c.pos()] = c.ch());
    
    String result = Arrays.stream(word)
        .map(str -> Objects.requireNonNullElse(str, " "))
        .collect(Collectors.joining());
    
    System.out.println(result);
}

Output:

Hello Word!
  • Related