Петля медленная

1

Пожалуйста, ознакомьтесь со следующим кодом

private StringBuffer populateStringWithUnmatchingWords(ArrayList<String>unmatchingWordsHolder)
    {
        StringBuffer unMatchingWordsStr = new StringBuffer("");

        for(int u=0;u<unmatchingWordsHolder.size();u++)
        {
             Iterator iterInWordMap = wordMap.entrySet().iterator();

             while(iterInWordMap.hasNext())
             {
                 Map.Entry mEntry = (Map.Entry)iterInWordMap.next();

                 if(mEntry.getValue().equals(unmatchingWordsHolder.get(u)))
                 {
                       //out.println(matchingWords.get(m)+" : "+true);
                       unMatchingWordsStr.append(mEntry.getKey());
                       unMatchingWordsStr.append(",");
                 }
              }
        }

        return unMatchingWordsStr;
    }

Это for loop занимает 8387ms для завершения. unmatchingWordsHolder тоже очень большой. wordMap - это HashMap и содержит около 5000 элементов.

Этот цикл будет искать, доступны ли элементы в unmatchingWordsHolder в wordMap. Если они доступны, они будут загружены в unMatchingWordsStr.

Есть ли способ ускорить эту задачу?

  • 0
    Можете ли вы предоставить код, используемый для определения времени выполнения этого метода, чтобы мы могли подтвердить, что предложенные решения являются улучшением или нет.
  • 0
    Вы должны предоставить пример ввода или код для генерации ввода, чтобы облегчить кому-либо тестирование.
Показать ещё 5 комментариев
Теги:
performance
arraylist
for-loop
hashmap

3 ответа

1
Лучший ответ

Помогает ли вообще использовать Collection.contains()? Это было бы гораздо читабельнее, если не больше, на мой взгляд. Это зависит от относительных размеров List и Map хотя, поскольку самый простой способ сделать это, это будет что-то вроде этого, хотя, поскольку вы повторяете Map и просматриваете List, если Map намного больше чем в List это не будет идеальным:

private StringBuffer populateStringWithUnmatchingWords(ArrayList<String>unmatchingWordsHolder) {
    StringBuffer unMatchingWordsStr = new StringBuffer();

    for (Entry<String, String> entry : wordMap.entrySet()) {
        if(unmatchingWordsHolder.contains(entry.getValue())) {
            //out.println(matchingWords.get(m)+" : "+true);
            unMatchingWordsStr.append(entry.getKey());
            unMatchingWordsStr.append(",");      
        }
    }
    return unMatchingWordsStr;
}

Как уже упоминалось в другом месте, если вам не нужна безопасность потоков, StringBuilder обычно предпочитает StringBuffer, но я не хочу связываться с вашими сигнатурами методов.

  • 0
    Почему бы не проверить наоборот? Я имею в виду, используйте: wordMap.contains(word) где word - это слово из unmatchingWordsHolder списка unmatchingWordsHolder . Это было бы намного быстрее.
  • 0
    Привет, код имеет ошибки. IDE говорит, что for-each not applicable to expression type required: array or java.lang.Iterable found: HashMap
Показать ещё 4 комментария
1

Вы повторяете каждый элемент Map. Лучший способ сделать это - использовать HashMap и использовать contains() чтобы определить, существует ли он в HashMap.

  • 1
    Спасибо за ответ. Проблема здесь в том, что мне нужно передать «значение», чтобы получить «ключ» на этой карте. Потому что то, что мне нужно, находится в «Ключе», а не в «значении».
0

Не уверен, правильно ли я получил ваш запрос проблемы, но если вы хотите вернуть строку, разделенную запятыми, всеми словами, которые находятся в другом наборе слов, вот как вы это сделаете в Java 8:

private String populateContainedWords(List<String> words, Set<String> wordSet)
{
  StringJoiner joiner = new StringJoiner(", ");

  words.stream().filter(wordSet::contains).forEach(joiner::add);

  return joiner.toString();
}

И если вы хотите иметь только отдельные слова в этой разделимой запятой строке, используйте следующий подход:

private String populateDistinctlyContainedWords(List<String> words, Set<String> wordSet)
{
  StringJoiner joiner = new StringJoiner(", ");

  words.stream().distinct().filter(wordSet::contains).forEach(joiner::add);

  return joiner.toString();
}

И если вы хотите, чтобы строка слов, разделенных запятыми, из списка words, которые НЕ содержатся в wordSet вот как это сделать:

private String populateDisjointWords(List<String> words, Set<String> wordSet)
{
  StringJoiner joiner = new StringJoiner(", ");

  words.stream().filter(n -> !wordSet.contains(n)).forEach(joiner::add);

  return joiner.toString();
}

Ещё вопросы

Сообщество Overcoder
Наверх
Меню