【问题标题】:Alphabetical sorting pretty slow字母排序很慢
【发布时间】:2018-08-29 16:14:31
【问题描述】:

这是我的问题:我有一个自定义对象列表,其中包含一个名为标签的字符串。这个列表很大但太大了,大约 1000 个对象。我想使用label 进行字母排序。

问题是,某些label 包含诸如É(eE 之类的字符作为第一个字符。所以我不得不使用函数deAccent()找到here来独立于重音或其他类似的东西对其进行排序。使用此函数,列表['Gab','eaaa','Éaa'] 会像['eaaa','Éaa','Gab'] 那样排序,而不是['eaaa','Gab','Éaa']。因为当我们使用compareTo方法时,ÉG之后。这是我所拥有的:

private List<Formula> sortFormulaList(List<Formula> formulaList) {
    // Sort all label alphabetically
    if (formulaList.size() > 0) {
        Collections.sort(formulaList, (formula1, formula2) ->
                deAccent(formula1.getLabel()).toLowerCase().compareTo(deAccent(formula2.getLabel().toLowerCase())));
    }
    return formulaList;
}

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

如果我不使用deAccent(),它对于我的目的来说已经足够快了,但是当我使用它时,它需要大约 1 到 3 秒来排序。

关于我如何进行这种排序的任何想法?或者让这个更快

【问题讨论】:

  • deAccent 方法你想做什么。也许可以优化一下
  • 例如,您可以预编译模式,而不是每次调用时都编译它。
  • @VenkataNarayanaMalireddy 我编辑了我的帖子以使其更清晰
  • 比较器平均会被调用 O(n log n) 次。因此,如果您对数据进行预处理,使得每个对象只调用一次 deAccent,您将获得很好的加速。
  • 感谢@Glains,通过对模式进行预编译,速度更快,几乎就像没有 deAccent() 一样

标签: java android sorting alphabetical


【解决方案1】:

考虑@Henry 的出色建议,Formula 可能看起来像这样:

public class Formula {
    private final String label;
    private final String deAccentedLabel;

    public Formula(String label) {
        this.label = label;
        this.deAccentedLabel = deAccent(label);
    }

    public String getLabel() {
        return label;
    }

    public String getDeAccentedLabel() {
        return comparableLabel;
    }


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

}

那么就可以这样使用了:

Collections.sort(formulaList, (formula1, formula2) -> formula1.getDeAccentedLabel().toLowerCase().compareTo(formula2.getDeAccentedLabel().toLowerCase());

但是,这会通过添加 public getDeAccentedLabel() 方法公开 deAccentedLabel

我在评论中的建议是隐藏deAccentedLabel 以保持Formula 的公共界面尽可能干净。因此,为了排序,Formula 提供了 Comparator 而不是其他类必须构建它Formula 看起来像这样:

public class Formula {
    private final String label;
    private final String comparableLabel;

    public Formula(String label) {
        this.label = label;
        this.comparableLabel = deAccent(label).toLowerCase();
    }

    public String getLabel() {
        return label;
    }

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

    public static Comparator<Formula> getLabelComparator() {
        return (formula1, formula2) -> formula1.comparableLabel.compareTo(formula2.comparableLabel);
    }

}

并像这样使用:

Collections.sort(formulaList, Formula.getLabelComparator());

【讨论】:

  • 好的,我明白了!这是从来没有做过的事情,非常感谢!
猜你喜欢
  • 2013-07-01
  • 1970-01-01
  • 2013-10-09
  • 1970-01-01
  • 2021-12-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-11-15
相关资源
最近更新 更多