我有adapter
扩展RecyclerView.Adapter<RecyclerView.ViewHolder>
并实施Filterable
。
我的getFilter()
实施是:
@Override
public Filter getFilter() {
return new Filter() {
@Override
protected void publishResults(CharSequence constraint, FilterResults results) {
mPersonListFiltered = (List<Person>) results.values;
notifyDataSetChanged();
}
@Override
protected FilterResults performFiltering(CharSequence constraint) {
FilterResults results = new FilterResults();
List<Person> filtered = new ArrayList<>();
if (constraint == null || constraint.length() == 0) {
results.count = mPersonList.size();
results.values = mPersonList;
} else {
String name, email, constr = Utils.removeDiacriticalMarks(constraint.toString());
for (Person person : mPersonList) {
name = Utils.removeDiacriticalMarks(person.getName().toLowerCase());
email = person.getEmail().toLowerCase();
if (name.contains(constr) || email.contains(constr)) {
filtered.add(person);
}
}
results.count = filtered.size();
results.values = filtered;
}
return results;
}
};
}
我希望在输入时过滤我的人员列表。如果我的列表大小不超过1k,这可以正常工作,但如果我将它扩展到5k,10k等等,它就开始变得迟钝。而且我理解为什么,对于每个我必须检查是否包含对其姓名和电子邮件的约束的人来说,这太糟糕了。 但我想知道在这种情况下,是否有很多条目,什么是最佳实现或替代方案来实现相同的结果,换句话说,一个快速过滤方法用于本地巨大的列表和&#34; on-the-飞&#34;打字。
感谢。
答案 0 :(得分:1)
您可以预过滤您的Person
条目。
您可以为所有单字符约束创建Map
个列表(实际上是Set
s),也可能是一些多字符约束。
Map<String, Set<Person>> mFilteredPersonMap = new HashMap<>();
当你获得适配器的Person
列表时,将它们添加到地图中的一个集合中:
for (Person person : mPersonList) {
String name = Utils.removeDiacriticalMarks(person.getName().toLowerCase());
for (char c : name.toCharArray()) {
if (Character.isWhitespace(c)) continue;
// you may want to skip other chars i.e. symbols
Set<Person> set = mFilteredPersonMap.get(Character.toString(c));
if (set == null) {
set = new HashSet<>();
mFilteredPersonMap.put(Character.toString(c), set);
}
set.add(person);
}
// do the same thing for email
}
我使用了名称中的每个字母,因为您在原始代码中使用了contains(constr)
。我的偏好是在单词边界(正则表达式"\\b(\\w)"
)之后搜索字符并将其用作地图的键。
然后将地图用作第一级过滤器:
@Override
protected FilterResults performFiltering(CharSequence constraint) {
FilterResults results = new FilterResults();
List<Person> filtered = new ArrayList<>();
if (constraint == null || constraint.length() == 0) {
results.count = mPersonList.size();
results.values = mPersonList;
} else {
String name, email, constr = Utils.removeDiacriticalMarks(constraint.toString());
String key = constr.substr(0, 1);
Set set = mFilteredPersonMap.get(key);
if (set != null) {
// now you are looping through a smaller collection
for (Person person : set) {
name = Utils.removeDiacriticalMarks(person.getName().toLowerCase());
email = person.getEmail().toLowerCase();
if (name.contains(constr) || email.contains(constr)) {
filtered.add(person);
}
}
}
results.count = filtered.size();
results.values = filtered;
}
return results;
}