2017-05-13 14 views
8

Mam klasy IndexEntry który wygląda tak:Jak uzyskać najczęstsze słowo w mapie i jego częstotliwość występowania za pomocą strumieni 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; 
    } 
    ... 
} 

jestem przechowywania obiektów tej klasy w Guava SortedSetMultimap (co pozwala na wiele wartości na klucz), gdzie jestem mapowania String słowo do niektórych IndexEntry s . Za kulisami mapuje każde słowo na SortedSet<IndexEntry>.

Próbuję wprowadzić rodzaj indeksowanej struktury słów do dokumentów i ich częstotliwości występowania w dokumentach.

Wiem, jak uzyskać liczyć z najbardziej popularnego słowa, ale nie mogę wydawać się, aby uzyskać samo słowo.

Oto co mam się liczyć z najbardziej wspólnej kadencji, gdzie entries jest SortedSetMultimap, wraz z metod pomocniczych:

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

próbuję Java Dowiedz 8 możliwości, ponieważ wydają bardzo przydatne . Jednak nie mogę sprawić, by strumień działał tak, jak chcę. Chcę być w stanie mieć zarówno słowo, jak i jego częstotliwość na końcu strumienia, ale jeśli nie, to z łatwością mogę uzyskać całkowite wystąpienie tego słowa.

Obecnie wciąż kończę z Stream<SortedSet<IndexEntry>>, z którym nie mogę nic zrobić. Nie wiem, jak uzyskać najczęstsze słowo bez częstotliwości, ale jeśli mam częstotliwość, nie mogę śledzić odpowiedniego słowa. Próbowałem stworzyć klasę POJO WordFrequencyPair do przechowywania obu, ale wtedy miałem tylko Stream<SortedSet<WordFrequencyPair>> i nie mogłem wymyślić, jak zamapować to na coś użytecznego.

Czego mi brakuje?

Odpowiedz

6

myślę, że będzie to lepsze projektowanie używać documentId jako klucz do TreeMultimap raczej niż 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); 
    } 

} 

Następnie można wdrożyć metody, które wcześniej z następujących czynności:

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

Więc załóżmy, że muszę zobaczyć wszystkie identyfikatory dokumentów, że dany wyraz był obecny wraz z liczbą wystąpień w danym dokumencie. W twoim przykładzie, jak miałbym to zrobić? –

+0

Napiszę metodę, żeby to zrobić i wyjaśnię, jak działa –

+0

Myślę, że to zadziała. Dzięki! –

0

Native rozwiązanie przez JDK:

entries.keySet().stream() 
    .collect(groupingBy(IndexEntry::getWord, summingInt(IndexEntry::getFrequency))) 
    .values().stream().max(Comparator.naturalOrder()).orElse(0L); 

albo przez StreamEx

StreamEx.of(entries.keySet()) 
    .groupingBy(IndexEntry::getWord, summingInt(IndexEntry::getFrequency)) 
    .values().stream().max(Comparator.naturalOrder()).orElse(0L); 
Powiązane problemy