Найти значение индекса символа, хранящегося в HashMap

Я пытаюсь напечатать значение индекса соответствующего символа столько раз, сколько оно появится using HashMap,

Например, скажем, у меня есть String str = "Hello World", Программа на данный момент отображает вхождение символов через {d=1, W=1, e=1, r=1, o=2, l=3, H=1},

Что я намерен достичь в качестве набора результатов {d=[9], o=[4, 6], r=[7], W=[5], H=[0], l=[2, 3, 8], e=[1]} где *=[*] представляет собой key=[indexValue],

(Символ пробела не должен учитываться в окончательном наборе результатов.)

import java.util.HashMap;
import java.util.Map;

public class ConcordanceOfStrings {

    public static void main(String[] args) {
        String str = "Hello World";

        //code to remove whitespaces        
        String newStr = str.replaceAll(" ", "");

        Map<Character, Integer> numCount = new HashMap<Character, Integer>(Math.min(newStr.length(), 26));

        System.out.println("The count is: ");
        for(int i=0; i<newStr.length(); i++){
                char charAt = newStr.charAt(i); 
                if(!numCount.containsKey(charAt)){  
                    numCount.put(charAt, 1);    
                }
                else{
                    numCount.put(charAt, numCount.get(charAt)+1);
                }
            }
            System.out.println(numCount);
        }
    }

2 ответа

Решение

Вам нужно нечто большее, чем просто карта, вам нужно что-то вроде карты>. Вот пример модификации вашего алгоритма:

    Map<Character, List<Integer>> positions = new HashMap<>();
    Map<Character, Integer> numCount = new HashMap<Character, Integer>(Math.min(newStr.length(), 26));

    for (int i = 0; i < newStr.length(); i++) {

        char charAt = newStr.charAt(i);
        if (!numCount.containsKey(charAt)) {
            numCount.put(charAt, 1);
        }
        else {
            numCount.put(charAt, numCount.get(charAt) + 1);
        }

        if(!positions.containsKey(charAt)){
            List<Integer> cPosition = new LinkedList<>();
            cPosition.add(i);
            positions.put(charAt, cPosition);
        }
        else{
            List<Integer> cPosition = positions.get(charAt);
            cPosition.add(i);
            //positions.put(charAt, cPosition); because of references there is no need to do this
        }
    }

Ты очень близко Прямо сейчас вы сохраняете результат в Map<Character, Integer>Таким образом, карта каждого символа соответствует количеству его появления в строке.

Чтобы сохранить все индексы, где появляется символ, вам нужно иметь Map<Character, List<Integer>>: каждый символ будет сопоставлен со списком целых чисел, который будет списком индексов, где появляется этот символ.

В вашем текущем коде вам просто нужно адаптировать логику, которая заполняет карту:

if(!numCount.containsKey(charAt)){  
    numCount.put(charAt, new ArrayList<>(Arrays.asList(i))); // <-- we store a list containing the first index i
    // numCount.put(charAt, 1);
} else{
    numCount.get(charAt).add(i); // <-- we add to the existing list the index i
    // numCount.put(charAt, numCount.get(charAt)+1);
}

В случае, когда карта не содержит символа, мы инициализируем отображение со списком, содержащим первый индекс i, Arrays.asList(i) возвращает список фиксированного размера, поэтому я завернул его в другой ArrayList,

В случае, когда карта уже содержит символ, нам просто нужно получить текущий список индексов и добавить тот, который мы только что нашли.


Если вы используете Java 8, весь ваш код может быть написан проще с помощью Streams:

Map<Character, List<Integer>> numCount = 
    IntStream.range(0, str.length())
             .filter(i -> str.charAt(i) != ' ')
             .boxed()
             .collect(Collectors.groupingBy(
                 i -> str.charAt(i),
                 Collectors.mapping(v -> v - 1, Collectors.toList())
             ));
Другие вопросы по тегам