使用大型阵列列表加速AutoComplete算法

时间:2017-03-01 14:44:26

标签: java android search arraylist autocomplete

我在Android应用上处理 InstantSearch功能,我想要实现的结果如下图所示。

http://stackoverflow.com/a/30429439/4907138

除了一件事,一切都正常。我正在使用的ArrayList是BIG(它包含近400k字)。因此,我在ListView上显示我的结果时遇到了性能问题(它很多)。

我很确定这是由我的Wordlist的长度造成的,因为减少了它的字数,一切都很顺利。

以下是我在适配器类中的过滤代码:

private class SearchResultsFilter extends Filter {

    @Override
    protected FilterResults performFiltering(CharSequence constraint) {

        FilterResults filterResults = new FilterResults();

        ArrayList<String> found = new ArrayList<>();
        if (constraint != null) {
            for (String word : MainActivity.WordList) {
                if (word.startsWith(constraint.toString().toLowerCase())) {
                    found.add(word);
                }
            }
        }

        filteredList = found;
        filterResults.values = found;
        filterResults.count = found.size();

        return filterResults;
    }

    @Override
    protected void publishResults(CharSequence constraint, FilterResults filterResults) {
        if (filterResults.count > 0) {
            Log.println(Log.INFO, "Results", "FOUND");
            results.clear();
            results.addAll((ArrayList<String>) filterResults.values);
            notifyDataSetChanged();
        } else {
            Log.println(Log.INFO, "Results", "-");
            results.clear();
            notifyDataSetInvalidated();
        }

    }
}

这就是我在 MainActivity

中加载ArrayList的方法
public static void loadDictionary(Activity activity) {
        //loading wordslist from file.
        BufferedReader line_reader = new BufferedReader(new InputStreamReader(activity.getResources().openRawResource(R.raw.wordlist)));
        String line;
        try {
            while ((line = line_reader.readLine()) != null) {
                WordList.add(line);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        Collections.sort(WordList);

谢谢大家,

度过愉快的一天。

1 个答案:

答案 0 :(得分:1)

我是Cesarsk项目的合作者,我注意到我们的问题是 performFiltering 方法。我们使用的Wordlist中有394.000+个元素,每次用户在SearchBar的EditText中键入一个字母时,performFiltering方法都会检查所有这些元素,即使它应该在每次迭代中排除一些。所以我实现了一种简单的方法来将列表拆分为不同的子列表。每个列表仅包含以字母表中的单个字母开头的单词。

意义:

  • 列表1仅包含以字母“ a
  • 开头的字词
  • 列表2仅包含以字母“ b

    开头的单词

    依旧......

然后我将所有列表放在 HashMap 中,其中 key =字母。这样做,现在我们只能选择与用户键入的第一个字母匹配的子列表,循环检查的字数少得多,立即产生结果。

以下是一些代码:

@Override
    protected FilterResults performFiltering(CharSequence constraint) {

        FilterResults filterResults = new FilterResults();

        ArrayList<Pair<String, String>> temp_list = null;
        ArrayList<Pair<String, String>> found = new ArrayList<>();

        if (constraint != null) {
            if (!(constraint.toString().isEmpty())) {
                temp_list = MainActivity.Wordlists_Map.get(constraint.toString().substring(0,1).toLowerCase());

                if(temp_list != null){
                    for(Pair<String, String> element : temp_list){
                        if(element.first.startsWith(constraint.toString().toLowerCase())){
                            found.add(element);
                        }
                    }
                }
            }
        }

        filterResults.values = found;
        filterResults.count = found.size();

        return filterResults;
    }