在Java中使用Lambda表示式統計詞頻

Subson發表於2017-05-31

在Java中使用Lambda表示式統計詞頻

常規方法

使用Java進行詞頻統計的常規方法步驟如下:

1. 初始化一個map物件例項(用於儲存單詞以及它的出現次數)和一個變數fre(用於詞頻臨時存放)
2. 遍歷每一個需要統計的單詞,進行如下操作
    a. 將fre賦值為1
    b. 判斷當前單詞在map中是否存在
        如果存在,則將fre加上該詞在map中存入詞頻
    c. 將當前單詞與fre存入map

以上步驟的程式碼實現如下:

Map<String, Integer> map = new HashMap<>();
int fre;
for(String word : words) {
    fre = 1;
    if(map.containsKey(word))
        fre += map.get(word);
    map.put(word, fre);
}

使用Lambda表示式

在學習閱讀State of the Lambda: Libraries Edition時,發現文中Collectors部分給出的最後一個程式碼例項存在一個小問題,即counting()方法返回的是長整型的資料型別Long,而Map卻是使用Integer接收,顯然是存在問題的。

文中的程式碼例項:

Pattern pattern = Pattern.compile(\\s+");
Map<String, Integer> wordFreq = 
    tracks.stream()
          .flatMap(t -> pattern.splitAsStream(t.name)) // Stream<String>
          .collect(groupingBy(s -> s.toUpperCase(),
                              counting()));

counting()方法的定義如下:

public static <T> Collector<T, ?, Long>
counting() {
    return reducing(0L, e -> 1L, Long::sum);
}

故而,需要使用自定義的counting()方法,如上,僅需要做如下修改即可:

Pattern pattern = Pattern.compile(\\s+");
Map<String, Integer> wordFreq =
        tracks.stream()
            .flatMap(t -> pattern.splitAsStream(t.name)) // Stream<String>
            .collect(groupingBy(s -> s.toUpperCase(),
                                Collectors.reducing(0, e -> 1, Integer::sum)));

假設所有需要統計的單詞存於List陣列中,那麼使用該方法進行詞頻統計程式碼如下:

// List<String> list = new ArrayList<>();
// list.add("aa a b A h z B");
// list.add("a a b A h z B");
// list.add("a a b A h z B");
// list.add("a a b A h z B");

Pattern pattern = Pattern.compile("\\s+");
Map<String, Integer> wordFreq =
    list.stream()
            .flatMap(t -> pattern.splitAsStream(t))
            .collect(groupingBy(s -> s, Collectors.reducing(0, e -> 1, Integer::sum)));

在集合(List)上呼叫stream()生成該集合元素的流檢視,然後採用將一個返回流的函式傳入flatMap(),這樣會產生每個單詞,最後將這些詞進行統計存入Map中。

相關文章