Java Comparator将计算得分1次或多次

时间:2017-11-11 14:15:59

标签: 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());

我认为它仍然可以进行更多优化。

1 个答案:

答案 0 :(得分:1)

有以下优化:

  • 在可行的情况下,应该使用double(“原始”数据类型)而不是Double(持有双精度的Object包装类)。
  • 在比较的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));
    }