2012-11-13 40 views
1

我試圖從TreeMap中的單個鍵檢索多個值。這個想法是,每個關鍵將鏈接到多個值,應該可以搜索。現在我遇到的麻煩是,當我只能從密鑰中獲得一個值時。Java TreeMap:從單個鍵檢索多個值

關鍵是一個字符串,該值是一個自定義對象,稱爲宋。歌曲包含多個元素。目標是從每首歌中逐字提取歌詞,並將每個單詞用作關鍵詞。該鍵然後鏈接到包含該鍵的每個樂曲(值)。

我已經搜索了StackOverFlow和一般的網絡技巧,我已經看到了一些,但沒有直接解決我的絆腳石。我看到的一個想法是將值更改爲某種數組或列表。我可能會在明天刷新大腦時嘗試。

無論如何,預先感謝您的任何提示和建議。是的,這是作業。不,我沒有標記是因爲我被告知,作業標籤不再被普遍使用。

代碼:

public class SearchByLyricsWords { 
    private static Song[] songs; 

    private static TreeMap<String, Song> lyricsTreeMap = new TreeMap<String, Song>(); 

    private static TreeSet<String> wordsToIgnoreTree = new TreeSet<String>(); 
    private static File wordsToIgnoreInput = new File("ignore.txt"); 
    private static String wordsToIgnoreString; 
    private static String[] wordsToIgnoreArray; 

    private Song[] searchResults; // holds the results of the search 
    private ArrayList<Song> searchList = new ArrayList<Song>(); 

public SearchByLyricsWords(SongCollection sc) throws FileNotFoundException { 

    // Create a string out of the ignore.txt file 
    Scanner scanInputFile = new Scanner(wordsToIgnoreInput); 
    String ignoreToken = scanInputFile.next(); 
    ignoreToken.toLowerCase(); 
    wordsToIgnoreString = ignoreToken + " "; 

    while (scanInputFile.hasNext()) { 
    ignoreToken = scanInputFile.next(); 
    wordsToIgnoreString = wordsToIgnoreString + ignoreToken + " "; 
    } 

    // Split the string created from ignore.txt 
    wordsToIgnoreArray = wordsToIgnoreString.split("[^a-zA-Z]+"); 

    // Fill a TreeSet from the wordsToIgnoreArray 
    for (int i = 0; i < wordsToIgnoreArray.length; i++) { 
    ignoreToken = wordsToIgnoreArray[i]; 
    wordsToIgnoreTree.add(ignoreToken); 
    } 

    // Fill TreeMap with lyrics words as the key, Song objects as the value 
    songs = sc.getAllSongs(); 

    for (int j = 0; j < songs.length; j++) { 
    Song currentSong = songs[j]; 
    String lyrics = currentSong.getLyrics();   
    TreeSet<String> lyricsFound = new TreeSet<String>(); 

    String lyricsToken; 
    String[] songLyricsArray; 
    songLyricsArray = lyrics.split("[^a-zA-Z]+"); 

    for (int k = 0; k < songLyricsArray.length; k++) { 
     lyricsToken = songLyricsArray[k]; 

     if (lyricsToken.length() <= 1) { 
      continue; 
     } 

     lyricsFound.add(lyricsToken); 
    } 

    lyricsFound.removeAll(wordsToIgnoreTree); 

    Iterator<String> iterator = lyricsFound.iterator(); 

    while(iterator.hasNext()) { 
     String currentWord = (String)iterator.next(); 
     lyricsTreeMap.put(currentWord, currentSong); 
    } 

    //System.out.println(lyricsTreeMap); // testing only 
    } 
} 


public Song[] search(String lyricsWords) { 

    lyricsWords = lyricsWords.toLowerCase(); 
    TreeSet<String> searchTree = new TreeSet<String>(); 
    String searchToken; 
    String[] lyricsWordsSearch = lyricsWords.split("[^a-zA-Z]+"); 

    for (int l = 0; l < lyricsWordsSearch.length; l++) { 
    searchToken = lyricsWordsSearch[l]; 

    if (searchToken.length() <= 1) { 
     continue;    
    } 
    searchTree.add(searchToken); 
    } 
    searchTree.removeAll(wordsToIgnoreTree); 

    Iterator<String> searchIterator = searchTree.iterator(); 

    while(searchIterator.hasNext()) { 
    String currentSearchWord = (String)searchIterator.next(); 
    Collection<Song> lyricsTreeCollection = lyricsTreeMap.values(); 

    while (lyricsTreeMap.containsKey(currentSearchWord) == true) { 

     Iterator collectionIterator = lyricsTreeCollection.iterator(); 

     while(collectionIterator.hasNext() && collectionIterator.next() == currentSearchWord) { 

      Song searchSong = lyricsTreeMap.get(currentSearchWord); 
      searchList.add(searchSong);   
     } 
    }   
    } 
    searchResults = searchList.toArray(new Song[searchList.size()]); 

    Arrays.sort(searchResults); 

    return searchResults; 
} 

回答

6

TreeMap只保留每個鍵一個值,as with all Map implementations

一個映射不能包含重複的鍵;每個鍵可以映射到最多一個值。

你的備選方案包括

  • 使用TreeMap<String, List<Song>>代替,並手動處理List值,並讓他們從番石榴,它(或多或少)的運作就像一個TreeMap<K, TreeSet<V>>更新
  • 使用e.g. a TreeMultimap,除了更好。 (披露:我貢獻番石榴)
+0

Darn。好吧,我的誤解。我知道鑰匙必須是唯一的,但我不明白他們只會映射到一個值。謝謝。 –

+0

我認爲內部結構應該是'Set'而不是'List'以存儲將自動省略密鑰的冗餘值的值。 –

+0

這在分配的上下文中是有意義的。我的印象是,在TreeMap中,這個值是作爲一個集合運行的。正如你所知道的,我仍然(努力)學習這些東西。謝謝回覆。 –

1

我想你shoule設置你的結構

Map<String, Set<Song>> 

這裏Set用作內部集合類而不是List。因爲它會自動忽略您的方案的重新值。

1

您需要使用這種格式初始化地圖,並設置:

Map<String, TreeSet<Song>>=new Map<String,treeSet<Song>>(); 

比你需要的循環多循環第一通歌曲集,然後拿到地圖鑰匙插入到您的地圖。 像這樣:

for(Song temp:songs){ 
     for(String word:temp.getLyrics().toLowerCase().split("[^a-zA-Z]+"){ 
      if(lyricsTreeMap.containsKey(word)){ 
        lyricsTreeMap.get(word).add(temp); 
    }