Java TreeMap:从单个键检索多个值
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/13355721/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Java TreeMap: Retrieving multiple values from a single key
提问by King Triumph
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.
我正在尝试从 TreeMap 中的单个键中检索多个值。这个想法是每个键都将链接到多个值并且应该是可搜索的。现在我遇到的麻烦是,当我只能从密钥中取回一个值时。
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.
键是一个字符串,值是一个名为 Song 的自定义对象。歌曲包含多种元素。目标是从每首歌曲中逐字提取歌词,并将每个单词用作关键字。然后该键链接到包含该键的每首歌曲(值)。
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.
我已经在 StackOverFlow 和网络上搜索了一般的技巧,我看到了一些,但没有直接解决我的绊脚石。我看到的一个想法是将值更改为某种数组或列表。明天当我的大脑恢复活力时,我可能会尝试。
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;
}
回答by Louis Wasserman
TreeMap
only keeps one value per key, as with all Map
implementations:
TreeMap
与所有Map
实现一样,每个键只保留一个值:
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.)
- 使用 a
TreeMap<String, List<Song>>
代替,并手动处理List
值并保持更新 - 使用例如
TreeMultimap
来自 Guava 的 a,它(或多或少)像 a 一样运行TreeMap<K, TreeSet<V>>
,但要好得多。(披露:我为番石榴做出了贡献。)
回答by Bhavik Ambani
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.
这里Set
用作内部 Collection 类而不是List
. 因为它会自动省略您的场景的冗余值。
回答by Maria
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 循环来首先通过歌曲集循环,然后将 Map 键插入到您的 Map 中。像这样:
for(Song temp:songs){
for(String word:temp.getLyrics().toLowerCase().split("[^a-zA-Z]+"){
if(lyricsTreeMap.containsKey(word)){
lyricsTreeMap.get(word).add(temp);
}