Java TreeMap: Retrieving multiple values from a single key
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 theList
values and keeping them updated - use e.g. a
TreeMultimap
from Guava, which (more or less) operates like aTreeMap<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.
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, 2022Comments
-
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; }