HashMap 實作 Java 中每個字元的出現次數統計
1.概述
計算字串中每個字元出現的次數是 Java 中常見且實用的任務。無論我們是在處理使用者輸入、分析文字或解決演算法問題,追蹤字元頻率通常都是關鍵步驟。
在本教程中,我們將探索基於HashMap
的簡單實現,以計算給定字串中每個字元的出現次數。
2.為什麼要使用HashMap
?
Java 中的HashMap
類別是一種鍵值資料結構,在大多數情況下允許恆定時間的檢索和插入。
為了計算字元頻率,我們可以將字串中每個唯一字元作為鍵,將其出現的次數作為值。在遍歷字串時,我們會檢查該字元是否已存在於映射中。如果存在,則將數值加一。如果不存在,則將其加一,初始計數為一。此方法提供了一種記錄字串中所有字元出現次數的有效方法。
3. Java實現
本節示範了兩種使用HashMap
來統計字串中字元出現次數的方法:一種是使用經典的 for 循環,另一種是使用 Java Streams。這兩種方法都在內部使用 Map 來儲存和統計字符,但在編碼風格和 API 使用上有所不同。
3.1. 使用簡單的 For 循環
最直接的方法是遍歷字串中的每個字符,並在HashMap
中更新其計數。這種方法易於理解且高效:
public static Map<Character, Integer> countCharactersWithLoop(String input) {
Map<Character, Integer> characterCountMap = new HashMap<>();
for (char ch : input.toCharArray()) {
characterCountMap.put(ch, characterCountMap.getOrDefault(ch, 0) + 1);
}
return characterCountMap;
}
我們的方法接受一個String
作為輸入,並傳回一個將每個字元與其頻率關聯起來的Map
。首先初始化一個空的HashMap
,其中的鍵是字符,值是字符的計數。
接下來,我們將字串轉換為字元數組並對其進行迭代。對於每個字符,我們使用 map 的getOrDefault()
方法來取得其當前計數(如果不存在則為0
),將其加一,然後更新 map。迭代完成後,該方法將傳回包含所有字元頻率的已填入 map。
這種簡單且有效率的方法會統計每個字符,包括空格和標點符號,同時區分大小寫字母。它還可以根據需要輕鬆調整,以忽略大小寫或過濾字元。
3.2. 使用 Java 流
Java Streams 提供了一種更具聲明性的方式來統計字元出現的次數,它將字串轉換為字元流,然後使用Collectors
對其進行分組和計數。這種方法更加簡潔,更具表現力:
public static Map<Character, Integer> countCharactersWithStreams(String input) {
return input.chars()
.mapToObj(c -> (char) c)
.collect(Collectors.groupingBy(
Function.identity(),
Collectors.collectingAndThen(Collectors.counting(), Long::intValue)
));
}
此方法首先使用input.chars()
將字串轉換為字元代碼的IntStream
,然後將每個程式碼對應到其對應的Character
物件。 Collectors.groupingBy Collectors.groupingBy()
操作將相同的字元分組,而Collectors.counting()
則計算每個字元出現的次數。
由於counting()
的結果為Long
,我們呼叫collectingAndThen()
函數,並將Long::intValue
轉換為Integer
,使返回類型與基於迴圈的方法一致。與先前的方法類似,此實作將大小寫字符視為不同的類型,並包含所有字符,包括空格和標點符號。
Stream API 為傳統迭代提供了一種簡潔且實用的替代方案,在處理更大的管道或更複雜的資料轉換時尤其有用。
4. 透過單元測試進行驗證
讓我們來看看兩個 JUnit 測試來驗證countCharactersWithLoop()
和countCharactersWithStreams()
方法是否針對簡單的輸入字串產生正確的輸出:
@Test
public void givenSimpleInput_whenCountingCharactersWithLoop_thenReturnsCorrectFrequencies() {
String input = "test";
Map<Character, Integer> result = CharacterFrequencyCounter.countCharactersWithLoop(input);
assertEquals(Integer.valueOf(2), result.get('t'));
assertEquals(Integer.valueOf(1), result.get('e'));
assertEquals(Integer.valueOf(1), result.get('s'));
assertEquals(3, result.size());
}
@Test
public void givenSimpleInput_whenCountingCharactersWithStreams_thenReturnsCorrectFrequencies() {
String input = "test";
Map<Character, Integer> result = CharacterFrequencyCounter.countCharactersWithStreams(input);
assertEquals(Integer.valueOf(2), result.get('t'));
assertEquals(Integer.valueOf(1), result.get('e'));
assertEquals(Integer.valueOf(1), result.get('s'));
assertEquals(3, result.size());
}
兩個測試都使用相同的輸入字串“test”
,並驗證每個字元的計數是否正確。它們確認字元't'
出現了兩次,而'e'
和's'
各出現了一次。此外,兩個映射都恰好包含三個條目,確保沒有包含多餘的字元。
這些測試驗證了這兩種方法的核心功能,證明它們可以產生等效且準確的結果。
5. 結論
在本文中,我們學習了兩種使用 Java 中的HashMap
來計算字串中字元頻率的方法:經典的 for 迴圈方法和使用 Java Streams 的更簡潔的解決方案。這兩種方法都能有效地將每個字符映射到其出現次數,並處理所有字符,包括空格和標點符號。
這些方法為字元頻率分析提供了堅實的基礎,並可根據各種文字處理需求進行調整。
像往常一樣,這裡討論的程式碼可以在 GitHub 上找到。