【问题标题】:Optimize filtering algorithm优化过滤算法
【发布时间】:2016-03-10 19:15:31
【问题描述】:

我目前正在开发一个 Android 应用程序,其 Activity 包含一个带有 aprox 的 RecyclerView。 1k 项(数据库查看器)。用户必须能够搜索这些项目,所以我使用这个过滤器实现了搜索:

class PersonFilter extends Filter
{
    private PersonViewAdapter adapter;
    private Person[] originalPeople;

    public PersonFilter(PersonViewAdapter adapter, Person[] unfiltered)
    {
        super();
        this.adapter = adapter;
        this.originalPeople = unfiltered;
    }

    @Override
    protected FilterResults performFiltering(CharSequence constraint)
    {
        constraint = constraint.toString().toLowerCase();
        FilterResults results = new FilterResults();

        if (constraint.length() == 0)
        {
            results.values = originalPeople;
            results.count = originalPeople.length;
        }
        else
        {
            ArrayList<Person> filtered = new ArrayList<>();

            for (Person p : originalPeople)
            {
                //region filtering
                if (p instanceof Student)
                {
                    Student s = (Student)p;
                    if (s.fullName.toLowerCase().contains(constraint) ||
                            s.mngClass.name.contains(constraint) ||
                            s.getShortUsername().contains(constraint) ||
                            s.getLongUsername().contains(constraint))
                    {
                        filtered.add(p);
                    }
                }
                else if (p instanceof Teacher)
                {
                    Teacher t = (Teacher)p;
                    if (t.fullName.toLowerCase().contains(constraint) ||
                            t.acronym.toLowerCase().contains(constraint) ||
                            t.getShortUsername().contains(constraint) ||
                            t.getLongUsername().contains(constraint))
                    {
                        filtered.add(p);
                    }
                }
                else
                {
                    if (p.fullName.toLowerCase().contains(constraint) ||
                            p.getShortUsername().contains(constraint) ||
                            p.getLongUsername().contains(constraint))
                    {
                        filtered.add(p);
                    }
                }
                //endregion
            }

            Person[] dummy = new Person[filtered.size()];
            results.values = filtered.toArray(dummy);
            results.count = filtered.size();
        }

        return results;
    }

    @Override
    protected void publishResults(CharSequence constraint, FilterResults results)
    {
        adapter.setPeople((Person[])results.values);
        adapter.notifyDataSetChanged();
    }
}

问题是,这种方式搜索效果不佳,而且由于我在 Java/Android 性能优化方面经验不足,我想知道我可以在这里改进什么。

这是“Person”类(如果需要):

public abstract class Person
{
    public int id;
    public String fullName;
    public String firstName;
    public String lastName;

    public String getShortUsername()
    {
        String ln = toUsernameForm(lastName);
        String username = ln.substring(0, Math.min(ln.length(), 7)) + firstName.substring(0, 1).toLowerCase();
        return username;
    }

    public String getLongUsername()
    {
        return toUsernameForm(firstName) + "." + toUsernameForm(lastName);
    }

    public static String toUsernameForm(String s)
    {
        return normalize(s.split("\\W")[0].toLowerCase().replace(" ", "")
                                        .replace("ä", "ae")
                                        .replace("ö", "oe")
                                        .replace("ü", "ue")
                                        .replace("ß", "ss"));
    }

    public static String normalize(String s)
    {
        String nfdNormalizedString = Normalizer.normalize(s, Normalizer.Form.NFD);
        Pattern pattern = Pattern.compile("\\p{InCombiningDiacriticalMarks}+");
        return pattern.matcher(nfdNormalizedString).replaceAll("");
    }
}

【问题讨论】:

    标签: java android filter


    【解决方案1】:

    这个版本应该减少类型转换。

    ArrayList<Person> filtered = new ArrayList<>();
    
    for (Person p : originalPeople)
    {
        //region filtering
        if (p.fullName.toLowerCase().contains(constraint) ||
            p.getShortUsername().contains(constraint) ||
            p.getLongUsername().contains(constraint))
        {
            filtered.add(p);
        }
        else if (p instanceof Student)
        {
            Student s = (Student) p;
            if (s.mngClass.name.contains(constraint))
            {
                filtered.add(p);
            }
        }
        else if (p instanceof Teacher)
        {
            Teacher t = (Teacher) p;
            if (t.acronym.toLowerCase().contains(constraint))
            {
                filtered.add(p);
            }
        }
        //endregion
    }
    
    results.values = filtered.toArray();
    results.count = filtered.size();
    

    似乎如果长用户名包含字符序列,短版本也可以(可能除了特殊字符)。您可以利用这一事实来减少比较。

    【讨论】:

    • 谢谢!我会尽快试试这个。如果我预先计算用户名,您认为会有很大的不同吗?
    • 如果您向用户显示所有三个用户名,则应该预先计算它们。不过,我建议不要使 Person 的实现复杂化。
    猜你喜欢
    • 1970-01-01
    • 2020-07-14
    • 2015-03-17
    • 2019-01-07
    • 1970-01-01
    • 2016-07-30
    • 2023-02-03
    • 1970-01-01
    相关资源
    最近更新 更多