我需要使用自定义比较器对列表进行排序: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(持有双精度的对象包装器类)。
所比较的citem中的一部分可以在构造函数中预先计算。 (citem甚至可能不再需要作为字段。)
一个值可能会被比较多次,因此可能会发生缓存,即从Item到其double值的映射。


所以

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));
    }

08-04 04:00