如何使用 Java 8 个流获取 Map 中出现频率最高的单词及其对应的出现频率?
How do I get the most frequent word in a Map and it's corresponding frequency of occurrence using Java 8 streams?
我有一个 class IndexEntry
看起来像这样:
public class IndexEntry implements Comparable<IndexEntry>
{
private String word;
private int frequency;
private int documentId;
...
//Simple getters for all properties
public int getFrequency()
{
return frequency;
}
...
}
我将此 class 的对象存储在 Guava SortedSetMultimap
中(允许每个键有多个值),我将 String
单词映射到某些 IndexEntry
s。在幕后,它将每个单词映射到 SortedSet<IndexEntry>
。
我正在尝试对文档及其在文档中出现的频率实施一种索引结构。
我知道如何获取最常用词的 count 个,但我似乎无法获取该词本身。
这是我必须获得最常见术语的计数,其中 entries
是 SortedSetMultimap
,以及辅助方法:
public int mostFrequentWordFrequency()
{
return entries
.keySet()
.stream()
.map(this::totalFrequencyOfWord)
.max(Comparator.naturalOrder()).orElse(0);
}
public int totalFrequencyOfWord(String word)
{
return getEntriesOfWord(word)
.stream()
.mapToInt(IndexEntry::getFrequency)
.sum();
}
public SortedSet<IndexEntry> getEntriesOfWord(String word)
{
return entries.get(word);
}
我正在尝试学习 Java 8 个功能,因为它们看起来非常有用。但是,我似乎无法让流按照我想要的方式工作。我希望能够在流的末尾同时拥有单词和它的频率,但除此之外,如果我有单词,我可以很容易地获得该单词的总出现次数。
目前,我一直以 Stream<SortedSet<IndexEntry>>
结尾,我对此无能为力。我不知道如何在没有频率的情况下获得最频繁的单词,但如果我有频率,我似乎无法跟踪相应的单词。我尝试创建一个 WordFrequencyPair
POJO class 来存储两者,但后来我只有一个 Stream<SortedSet<WordFrequencyPair>>
,我不知道如何将其映射到有用的东西。
我错过了什么?
我认为使用 documentId
作为 TreeMultimap
的键而不是 word
会是一个更好的设计:
import com.google.common.collect.*;
public class Main {
TreeMultimap<Integer, IndexEntry> entries = TreeMultimap.<Integer, IndexEntry>create(Ordering.arbitrary(), Ordering.natural().reverse());
public static void main(String[] args) {
// Add elements to `entries`
// Get the most frequent word in document #1
String mostFrequentWord = entries.get(1).first().getWord();
}
}
class IndexEntry implements Comparable<IndexEntry> {
private String word;
private int frequency;
private int documentId;
public String getWord() {
return word;
}
public int getFrequency() {
return frequency;
}
public int getDocumentId() {
return documentId;
}
@Override
public int compareTo(IndexEntry i) {
return Integer.compare(frequency, i.frequency);
}
}
然后您可以使用以下方法实现之前的方法:
public static int totalFrequencyOfWord(String word) {
return entries.values()
.stream()
.filter(i -> word.equals(i.getWord()))
.mapToInt(IndexEntry::getFrequency)
.sum();
}
/**
* This method iterates through the values of the {@link TreeMultimap},
* searching for {@link IndexEntry} objects which have their {@code word}
* field equal to the parameter, word.
*
* @param word
* The word to search for in every document.
* @return
* A {@link List<Pair<Integer, Integer>>} where each {@link Pair<>}
* will hold the document's ID as its first element and the frequency
* of the word in the document as its second element.
*
* Note that the {@link Pair} object is defined in javafx.util.Pair
*/
public static List<Pair<Integer, Integer>> totalWordUses(String word) {
return entries.values()
.stream()
.filter(i -> word.equals(i.getWord()))
.map(i -> new Pair<>(i.getDocumentId(), i.getFrequency()))
.collect(Collectors.toList());
}
JDK 的原生解决方案:
entries.keySet().stream()
.collect(groupingBy(IndexEntry::getWord, summingInt(IndexEntry::getFrequency)))
.values().stream().max(Comparator.naturalOrder()).orElse(0L);
或通过StreamEx
StreamEx.of(entries.keySet())
.groupingBy(IndexEntry::getWord, summingInt(IndexEntry::getFrequency))
.values().stream().max(Comparator.naturalOrder()).orElse(0L);
我有一个 class IndexEntry
看起来像这样:
public class IndexEntry implements Comparable<IndexEntry>
{
private String word;
private int frequency;
private int documentId;
...
//Simple getters for all properties
public int getFrequency()
{
return frequency;
}
...
}
我将此 class 的对象存储在 Guava SortedSetMultimap
中(允许每个键有多个值),我将 String
单词映射到某些 IndexEntry
s。在幕后,它将每个单词映射到 SortedSet<IndexEntry>
。
我正在尝试对文档及其在文档中出现的频率实施一种索引结构。
我知道如何获取最常用词的 count 个,但我似乎无法获取该词本身。
这是我必须获得最常见术语的计数,其中 entries
是 SortedSetMultimap
,以及辅助方法:
public int mostFrequentWordFrequency()
{
return entries
.keySet()
.stream()
.map(this::totalFrequencyOfWord)
.max(Comparator.naturalOrder()).orElse(0);
}
public int totalFrequencyOfWord(String word)
{
return getEntriesOfWord(word)
.stream()
.mapToInt(IndexEntry::getFrequency)
.sum();
}
public SortedSet<IndexEntry> getEntriesOfWord(String word)
{
return entries.get(word);
}
我正在尝试学习 Java 8 个功能,因为它们看起来非常有用。但是,我似乎无法让流按照我想要的方式工作。我希望能够在流的末尾同时拥有单词和它的频率,但除此之外,如果我有单词,我可以很容易地获得该单词的总出现次数。
目前,我一直以 Stream<SortedSet<IndexEntry>>
结尾,我对此无能为力。我不知道如何在没有频率的情况下获得最频繁的单词,但如果我有频率,我似乎无法跟踪相应的单词。我尝试创建一个 WordFrequencyPair
POJO class 来存储两者,但后来我只有一个 Stream<SortedSet<WordFrequencyPair>>
,我不知道如何将其映射到有用的东西。
我错过了什么?
我认为使用 documentId
作为 TreeMultimap
的键而不是 word
会是一个更好的设计:
import com.google.common.collect.*;
public class Main {
TreeMultimap<Integer, IndexEntry> entries = TreeMultimap.<Integer, IndexEntry>create(Ordering.arbitrary(), Ordering.natural().reverse());
public static void main(String[] args) {
// Add elements to `entries`
// Get the most frequent word in document #1
String mostFrequentWord = entries.get(1).first().getWord();
}
}
class IndexEntry implements Comparable<IndexEntry> {
private String word;
private int frequency;
private int documentId;
public String getWord() {
return word;
}
public int getFrequency() {
return frequency;
}
public int getDocumentId() {
return documentId;
}
@Override
public int compareTo(IndexEntry i) {
return Integer.compare(frequency, i.frequency);
}
}
然后您可以使用以下方法实现之前的方法:
public static int totalFrequencyOfWord(String word) {
return entries.values()
.stream()
.filter(i -> word.equals(i.getWord()))
.mapToInt(IndexEntry::getFrequency)
.sum();
}
/**
* This method iterates through the values of the {@link TreeMultimap},
* searching for {@link IndexEntry} objects which have their {@code word}
* field equal to the parameter, word.
*
* @param word
* The word to search for in every document.
* @return
* A {@link List<Pair<Integer, Integer>>} where each {@link Pair<>}
* will hold the document's ID as its first element and the frequency
* of the word in the document as its second element.
*
* Note that the {@link Pair} object is defined in javafx.util.Pair
*/
public static List<Pair<Integer, Integer>> totalWordUses(String word) {
return entries.values()
.stream()
.filter(i -> word.equals(i.getWord()))
.map(i -> new Pair<>(i.getDocumentId(), i.getFrequency()))
.collect(Collectors.toList());
}
JDK 的原生解决方案:
entries.keySet().stream()
.collect(groupingBy(IndexEntry::getWord, summingInt(IndexEntry::getFrequency)))
.values().stream().max(Comparator.naturalOrder()).orElse(0L);
或通过StreamEx
StreamEx.of(entries.keySet())
.groupingBy(IndexEntry::getWord, summingInt(IndexEntry::getFrequency))
.values().stream().max(Comparator.naturalOrder()).orElse(0L);