Java TreeMap: Retrieving multiple values from a single key

14,290

Solution 1

TreeMap only keeps one value per key, as with all Map implementations:

A map cannot contain duplicate keys; each key can map to at most one value.

Your alternatives include

  • use a TreeMap<String, List<Song>> instead, and manually deal with the List values and keeping them updated
  • use e.g. a TreeMultimap from Guava, which (more or less) operates like a TreeMap<K, TreeSet<V>>, except a lot better. (Disclosure: I contribute to Guava.)

Solution 2

You need to use this format to initialize the map and set:

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

Than you will need a multiple for loops to loop first thru the song set and than get the Map keys to insert into your Map. Like so:

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

Solution 3

I think you shoule set your structure as

Map<String, Set<Song>>

Here Set is used as inner Collection class rather then List. Because it will automatically omit the redundent value for your scenario.

Share:
14,290
King Triumph
Author by

King Triumph

I'm fairly new to programming. I'm in my second semester of learning Java. I really like it so far and hope to continue with Java as well as add other programming languages to my knowledge base.

Updated on June 23, 2022

Comments

  • King Triumph
    King Triumph almost 2 years

    I'm trying to retrieve multiple values from a single key in a TreeMap. The idea is that each key will link to multiple values and should be searchable. Right now the trouble I'm running into is that when I am only able to get one value back from the key.

    The key is a String and the value is a custom object, called Song. Song contains multiple elements. The goal is to extract the lyrics, word by word, from each song and use each word as a key. The key then links to each Song (the value) that contains the key.

    I've searched StackOverFlow and the web in general for tips, and I've seen a few, but nothing that directly addresses my stumbling block. One idea I saw was to change the value into some kind of array or list. I may try that tomorrow when my brain is refreshed.

    Anyway, thanks in advance for any tips and advice. And yes, this is homework. No, I did not tag is because I was informed that the homework tag is no longer commonly in use.

    Code:

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