2017-05-13 13 views
8

I는 다음과 같습니다 클래스 IndexEntry 있습니다지도에서 가장 자주 나오는 단어를 얻으려면 어떻게해야합니까? Java 8 스트림을 사용하여 해당 발생 빈도가 있습니까?

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; 
    } 
    ... 
} 

나는 어떤 IndexEntry들에 String 단어를 매핑하고 (키마다 여러 값을 허용) 구아바 SortedSetMultimap이 클래스의 객체를 포함하고있다 . 뒤에서는 각 단어를 SortedSet<IndexEntry>으로 매핑합니다.

문서 내의 단어와 문서 내의 발생 빈도의 색인 구조를 구현하려고합니다.

나는 가장 일반적인 단어 인 으로 계산하는 방법을 알고 있지만 단어 자체를 얻을 수없는 것 같습니다. 그들은 정말 유용한 것 때문에 자바 8 개 기능을 배우려고 노력하고

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); 
} 

을 : 여기

내가 헬퍼 방법과 함께, entriesSortedSetMultimap입니다 가장 일반적인 용어의 수를 얻을 수있을 것입니다 . 그러나 스트림이 원하는 방식으로 작동하지 못하는 것 같습니다. 스트림의 끝 부분에있는 단어와 빈도를 모두 가질 수 있기를 원하지만 그 단어가 없으면 그 단어의 전체 어커런스를 매우 쉽게 얻을 수 있습니다.

현재까지 나는 아무 것도 할 수없는 Stream<SortedSet<IndexEntry>>으로 끝납니다. 나는 빈도가없는 가장 빈번한 단어를 얻는 방법을 모르지만, 빈도가 있다면 나는 해당 단어를 추적하는 것처럼 보이지 않습니다. WordFrequencyPair POJO 클래스를 둘 다 저장하려고 시도했지만 그 다음에 방금 Stream<SortedSet<WordFrequencyPair>>이 있었고 유용하게 매핑하는 방법을 알 수 없었습니다.

무엇이 누락 되었습니까?

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); 
    } 

} 

당신은 당신이 다음과 같이 이전에했던 방법을 구현할 수 있습니다 :

답변

6

나는 오히려 word보다 TreeMultimap의 핵심으로 documentId를 사용하는 더 나은 디자인이 될 것이라고 생각

JDK에 의해
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()); 
} 
+0

함으로써, 나는 주어진 단어가 문서의 발생 횟수와 함께,에 있던 문서 식별자를 모두 볼 필요가 있다고 가정합니다. 귀하의 예를 들어, 나는 그 일을 어떻게 할 것입니까? –

+0

그 방법을 설명하고 어떻게 작동하는지 설명해 드리겠습니다. –

+0

이 방법이 효과가 있다고 생각합니다. 감사! –

0

기본 솔루션 :

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);