Java TreeMap: получение нескольких значений из одного ключа

Я пытаюсь получить несколько значений из одного ключа в TreeMap. Идея состоит в том, что каждый ключ будет ссылаться на несколько значений и должен быть доступен для поиска. Прямо сейчас проблема, с которой я сталкиваюсь, состоит в том, что, когда я могу получить только одно значение из ключа.

Ключ представляет собой строку, а значение представляет собой пользовательский объект, который называется Song. Песня содержит несколько элементов. Цель состоит в том, чтобы извлечь слова, слово за словом, из каждой песни и использовать каждое слово в качестве ключа. Затем ключ связывается с каждой композицией (значением), содержащей ключ.

Я искал в 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;
}

3 ответа

TreeMap сохраняет только одно значение на ключ, как и для всех Map реализации:

Карта не может содержать дубликаты ключей; каждый ключ может соответствовать максимум одному значению.

Ваши альтернативы включают

  • использовать TreeMap<String, List<Song>> вместо этого, и вручную справиться с List ценности и их обновление
  • используйте, например, TreeMultimap из Гуавы, которая (более или менее) работает как TreeMap<K, TreeSet<V>>, кроме намного лучше. (Раскрытие: я помогаю гуаве.)

Я думаю, что вы должны установить свою структуру как

Map<String, Set<Song>>

Вот Set используется как внутренний класс Collection, а не List, Потому что он автоматически пропустит избыточное значение для вашего сценария.

Вам нужно использовать этот формат для инициализации карты и установить:

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

Чем вам понадобится несколько циклов for, чтобы зациклить сначала набор песен, а затем получить ключи карты для вставки в вашу карту. Вот так:

    for(Song temp:songs){
       for(String word:temp.getLyrics().toLowerCase().split("[^a-zA-Z]+"){
             if(lyricsTreeMap.containsKey(word)){
                  lyricsTreeMap.get(word).add(temp);
    }
Другие вопросы по тегам