Java Comparator会计算1次或多次分数

标签 java

我需要使用自定义比较器对列表进行排序:Collections.sort(availableItems, new TextClassifyCnnComparator(citem, false))

class TextClassifyCnnComparator implements Comparator<Item> {

    private Item citem;
    private boolean isAsc;

    public TextClassifyCnnComparator(Item citem) {
        this(citem, true);
    }

    public TextClassifyCnnComparator(Item citem, boolean isAsc) {
        this.citem = citem;
        this.isAsc = isAsc;
    }

    private Double calcSimilarScore(Item item) {
        return item.getEncodedFromCNN().dotProduct(citem.getEncodedFromCNN());
    }

    @Override
    public int compare(Item o1, Item o2) {
        if (isAsc) {
            return calcSimilarScore(o1).compareTo(calcSimilarScore(o2));
        }
        return calcSimilarScore(o2).compareTo(calcSimilarScore(o1));
    }

}

Java 是否会为每个项目映射并调用 calcSimilarScore 1 次,还是会被调用多次(每个元组 2 项目 1 次)?

如果它调用多次,我该如何优化这个任务?

========更新1:===============

我已经折射了我的比较器:

class TextClassifyCnnComparator implements Comparator<Integer> {

    private boolean isAsc;
    private List<Double> list;

    public TextClassifyCnnComparator(Item citem, List<Item> list) {
        this(citem, list, true);
    }

    public TextClassifyCnnComparator(Item citem, List<Item> list, boolean isAsc) {
        this.list = list.parallelStream().map(item -> calcSimilarScore(item, citem)).collect(Collectors.toList());
        this.isAsc = isAsc;
    }

    private Double calcSimilarScore(Item item1, Item item2) {
        return item1.getEncodedFromCNN().dotProduct(item2.getEncodedFromCNN());
    }

    public List<Integer> createIndexes() {
        List<Integer> indexes = new ArrayList<>();
        for (int i = 0; i < list.size(); i++) {
            indexes.add(i); // Autoboxing
        }
        return indexes;
    }

    @Override
    public int compare(Integer index1, Integer index2) {
        // Autounbox from Integer to int to use as array indexes
        if (isAsc)
            return list.get(index1).compareTo(list.get(index2));
        return list.get(index2).compareTo(list.get(index1));
    }

}

...

TextClassifyCnnComparator comparator = new TextClassifyCnnComparator(citem, availableItems);
List<Integer> indexes = comparator.createIndexes();
Collections.sort(indexes, comparator);

return indexes.parallelStream().map(index -> availableItems.get(index)).collect(Collectors.toList());

我认为它还可以进一步优化。

最佳答案

有以下优化:

  • 只要可行,就应该使用 double(“原始”数据类型)而不是 Double(持有 double 的对象包装类)。
  • 比较的citem的一部分可以在构造函数中预先计算。 (citem 甚至可能不再需要作为字段。)
  • 一个值可能会被比较多次,因此可以使用缓存,即从 Item 到其 double 值的 Map。

所以

class TextClassifyCnnComparator implements Comparator<Item> {

    private final Item citem;
    private final boolean isAsc;
    private final ECNN encodedFromCNN;

    private Map<Item, Double> scores = new HashMap<>();

    public TextClassifyCnnComparator(Item citem) {
        this(citem, true);
    }

    public TextClassifyCnnComparator(Item citem, boolean isAsc) {
        this.citem = citem;
        this.isAsc = isAsc;
        encodedFromCNN = citem.getEncodedFromCNN();
    }

    private double calcSimilarScore(Item item) {
        Double cached = scores.get(item);
        if (cached != null) {
            return cached;
        }
        double score = item.getEncodedFromCNN().dotProduct(encodedFromCNN);
        scores.put(Item, score);
        return score;
    }

    @Override
    public int compare(Item o1, Item o2) {
        if (isAsc) {
            return calcSimilarScore(o1).compareTo(calcSimilarScore(o2));
        }
        return calcSimilarScore(o2).compareTo(calcSimilarScore(o1));
    }

}

或者 Java 8 中的时尚:

    private double calcSimilarScore(Item item) {
        return scores.computeIfAbsent(item,
            it -> it.getEncodedFromCNN().dotProduct(encodedFromCNN));
    }

关于Java Comparator会计算1次或多次分数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47238852/

相关文章:

java - 如何设置一些像Animation-List一样重复的字符串?

java - 得到错误 org.springframework.beans.factory.NoSuchBeanDefinitionException : No bean named 'springSecurityFilterChain' is defined

Java 1.5 脚本引擎

Tomcat 上的 Java Web 应用程序 - 显示用户上传的文件

java - R 无法在 Eclipse 中正确安装...Java 问题?

java - 进程需要重定向输入

java - Android:如何在更新 UI 的同时创建循环延迟

java - 如何在露天访问 session 工厂(数据源)?

JAVA .wait() 用于在运行方法之前等待 android studio

java - 针对特定于操作系统的 JRE 进行编码