如何更快地检查多个包含操作?

时间:2017-11-08 07:41:34

标签: java linked-list

我有一个String列表如下。我想基于此列表是否具有多个具有相同值的元素来进行一些计算。

我有近120k元素,当我运行此代码时,它运行得太慢了。有没有比包含方法更快的方法?

List<String> words= getWordsFromDB();  //words list has nearly 120k elements
List<String> tempWordsList = new LinkedList<String>();  //empty list

String[] keys = getKeysFromDB();
List<String> tempKeysList = new LinkedList<String>();

for (int x = 0; x < words.size(); x++) {

    if (!tempWordsList.contains(words.get(x))) {
      tempWordsList.add(words.get(x));

      String key= keys[x];
      tempKeysList.add(key);
    } else {
        int index = tempWordsList.indexOf(words.get(x));

        String m = tempKeysList.get(index);
        String n = keys[x];
        if (!m.contains(n)) {
            String newWord = m + ", " + n;
            tempKeysList.set(index, newWord);
        }
    }
}

编辑:单词列表来自数据库,问题是有服务不断更新并将数据插入此表。我没有任何访问此服务的权限,还有其他应用程序正在使用同一个表。

EDIT2:我已更新完整代码。

4 个答案:

答案 0 :(得分:2)

LinkedList.get()在O(N)时间内运行。使用ArrayList和O(1)查找时间,或者通过使用迭代器完全避免索引查找:

for (String word : words) {
    if (!tempList.contains(word)) {
        tempList.add(word);
    } else {
        int firstIndex = tempList.indexOf(word);
        //do some calculations
    }
}

免责声明:上述内容是根据wordsLinkedList的可疑假设撰写的。我仍然会推荐增强型for循环,因为它更常规,其时间复杂度不依赖于实现。无论哪种方式,下面的建议仍然存在。

您可以使用tempList替换HashMap来进一步改进。这样可以避免contains()indexOf()

的O(N)费用
Map<String, Integer> indexes = new HashMap<>();
int index = 0;
for (String word : words) {
    Integer firstIndex = indexes.putIfAbsent(word, index++);
    if (firstIndex != null) {
        //do some calculations
    }
}

根据您的最新更新,您似乎正在尝试对&#34;键&#34;进行分组。通过他们相应的&#34;字&#34;。如果是这样,你可能会给溪流一个旋转:

List<String> words = getWordsFromDB();
String[] keys = getKeysFromDB();
Collection<String> groupedKeys = IntStream.range(0, words.size())
        .boxed()
        .collect(Collectors.groupingBy(
                words::get,
                LinkedHashMap::new,   // if word order is significant
                Collectors.mapping(
                        i -> keys[i],
                        Collectors.joining(", "))))
        .values();

但是,正如评论中所提到的,最好将此逻辑移到数据库查询中。

答案 1 :(得分:2)

您每个单词都会搜索两次列表:一次用于contains(),一次用于indexOf()。您可以将contains()替换为indexOf(),将结果测试为-1,否则重复使用结果而不是再次调用indexOf()。但是你肯定使用了错误的数据结构。您到底需要a到底是什么? 您需要a吗?如果您需要将其他数据与每个单词相关联,我会使用HashSetHashMap

答案 2 :(得分:2)

CString sysCommand;
sysCommand.Format(_T("powershell.exe -executionpolicy unrestricted /C '%s' 
%s"), psFile, parameter);

答案 3 :(得分:0)

实际上,tempList使用线性复杂性时间方法:

if (!tempList.contains(words.get(x))) {

int a = tempList.indexOf(words.get(x));

这意味着在每次调用它们时,列表平均迭代为一半 此外,这些都是多余的。
只能调用indexOf()

for (int x = 0; x < words.size(); x++) {

    int indexWord = tempList.indexOf(words.get(x));

    if (indexWord != -1) {
      tempList.add(words.get(x));
    } else {        
      //do some calculations by using indexWord
    }
}

但要改善所有访问权限,您应该更改结构:将LinkedList换行或替换为LinkedHashSet
LinkedHashSet将保留实际行为,因为作为List,它定义了迭代排序,即元素插入集合的顺序,但它也使用散列功能来改进对其元素的时间访问。