2017-11-11 52 views
0

我需要用我的自定義比較列表排序:Collections.sort(availableItems, new TextClassifyCnnComparator(citem, false))Java的比較將計算得分1次或數次

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

我認爲它仍然可以優化更多。

+0

比較比較傳遞給'比較()兩個對象'方法,爲什麼你的比較器的構造函數接受一個'項目'作爲一個參數?爲什麼你會期望我們知道如何優化我們從未見過的代碼(比如'getEncodedFromCNN()'和'dotProduct()')? – alfasin

+0

@alfasin我想比較'Item'與列表中每個'Item'之間的相似分數。那是問題嗎? 'calcSimilarScore'函數內部的任何內容都不在乎 –

+0

您可以通過調用'compare()'來比較任何兩個項目,但是在這裏您爲每個項目創建一個比較器,這似乎是錯誤的,甚至是誤導性的,因爲傳遞比較的兩個項目不會相互比較,而是與第三個項目進行比較,然後比較結果。 – alfasin

回答

1

有下列優化:

  • 應該使用double(「原始」數據類型)而不是Double(對象包裝類保持一個雙),在可行的情況。
  • 在比較citem的一部分可以在構造函數中預先計算。 (citem可能甚至不再需要作爲字段)。
  • 值可能會被多次比較,因此緩存是可能的,即從項目到其雙倍值的映射。

所以

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