2017-07-03 93 views
1

我有一個需要(下面是一個簡單的例子)比賽分爲以下順序排序的程序:優化排序方法

PIT 
PREDICTIONS 
Match 1 
Match 2 
Quarters 1 Match 1 
Quarters 1 Match 2 
Quarters 2 Match 1 
Semis 1 
Semis 2 
Finals 1 
Finals 2 

注:可以有無限的較量,宿舍1 - 4只(無限次級比賽),無限次半決賽和無限制決賽。

我有一個分數分配給上述標題之一下面的方法:

public static long getMatchScore(String name) { 
    long score = 0; 
    String matchName = name.toLowerCase(); 
    String[] tokens = matchName.split("\\s+"); 

    if(matchName.startsWith("pit")) score -= 100000; 
    else if(matchName.startsWith("predictions")) score -= 1000; 
    else if(matchName.startsWith("quals")) score = Integer.parseInt(matchName.split("\\s+")[1]); 
    else if(matchName.startsWith("quarters")) { 
     if(Integer.parseInt(tokens[1]) == 1) score += 1000; 
     else if(Integer.parseInt(tokens[1]) == 2) score += 10000; 
     else if(Integer.parseInt(tokens[1]) == 3) score += 100000; 
     else if(Integer.parseInt(tokens[1]) == 4) score += 1000000; 

     score += Integer.parseInt(tokens[3]); 
    } 
    else if(matchName.startsWith("semis")) { 
     if(Integer.parseInt(tokens[1]) == 1) score += 10000000; 
     else if(Integer.parseInt(tokens[1]) == 2) score += 100000000; 

     score += Integer.parseInt(tokens[3]); 
    } 
    else if(matchName.startsWith("finals")) { 
     score += 1000000000; 
     score += Integer.parseInt(tokens[1]); 
    } 
    return score; 
} 

那麼Java方法compareTo()來排序。有沒有更好的方法來做到這一點,而不是像100000000那樣分配大量數字。

+2

把所有規則放在'enum'我的客人 – Jerry06

+0

請告訴我們你是怎麼稱呼這個的。 –

+1

您可以指定0,1,2,3,4,5等小數字,但它不會有任何區別。實際的排序是如果有大量的項目需要花費時間,並且如果沒有大量的項目,考慮試圖改進該代碼是毫無意義的,因爲它將全部以大約納秒。 – EJP

回答

2

這個需要將代碼中的邏輯嵌入到Comparable類中。

import java.util.ArrayList; 
import java.util.Collections; 
import java.util.List; 

public class MatchDescription implements Comparable<MatchDescription> { 

    private MatchType matchType; 
    private int matchOrder = 0; 
    private int subMatchOrder = 0; 

    public MatchDescription(String name) { 
     String matchName = name.toLowerCase().trim(); 
     String[] tokens = matchName.split("\\s+"); 

     matchType = MatchType.getByName(tokens[0]); 

     if (matchType.hasMatchOrder()) { 
      matchOrder = Integer.parseInt(tokens[1]); 
     } 
     if (matchType.hasSubmatches()) { 
      subMatchOrder = Integer.parseInt(tokens[3]); 
     } 
    } 

現在,方法的compareTo(T)和equals(對象)正在使用的邏輯覆蓋的比賽順序,分階等

@Override 
    public int compareTo(MatchDescription other) { 
     if (this.matchType == other.matchType) 
      if (this.matchOrder == other.matchOrder) 
       return (this.subMatchOrder - other.subMatchOrder); 
      else 
       return (this.matchOrder - other.matchOrder); 
     else 
      return (this.matchType.getMatchTypeOrder() - other.matchType.getMatchTypeOrder()); 
    } 

    @Override 
    public boolean equals(Object other) { 
     return (other instanceof MatchDescription) && 
       (((MatchDescription) other).matchType == this.matchType) && 
       (((MatchDescription) other).matchOrder == this.matchOrder); 
    } 

匹配類型經由內枚舉管理:

private enum MatchType { 
     PIT("PIT",     1, false, false), 
     PREDICTIONS("PREDICTIONS", 2, false, false), 
     MATCH("Match",    3, true, false), 
     QUARTERS("Quarters",  4, true, true), 
     SEMIS("Semis",    5, true, true), 
     FINALS("Finals",   6, true, false) 
     ; 

     private String name; 
     private int matchTypeOrder; 
     private boolean hasMatchOrder; 
     private boolean hasSubmatches; 

     MatchType(String name, int matchTypeOrder, boolean hasMatchOrder, boolean hasSubmatches) { 
      this.name   = name; 
      this.matchTypeOrder = matchTypeOrder; 
      this.hasMatchOrder = hasMatchOrder; 
      this.hasSubmatches = hasSubmatches; 
     } 

     public boolean hasMatchOrder() { 
      return hasMatchOrder; 
     } 

     public boolean hasSubmatches() { 
      return hasSubmatches; 
     } 

     public static MatchType getByName(String matchName) { 
      for (MatchType value : values()) { 
       if (value.getName().equalsIgnoreCase(matchName)) 
        return value; 
      } 
      return null; 
     } 

     private String getName() {   
      return name; 
     } 

     public int getMatchTypeOrder() {    
      return matchTypeOrder; 
     } 
    } 

最後,的toString()給出了對象很好:

public String toString() { 
     String description = matchType.getName(); 
     if (matchType.hasMatchOrder()) { 
      description += " " + matchOrder; 

      if (matchType.hasSubmatches()) 
       description += " Match " + subMatchOrder; 
     } 

     return description; 
    } 

這是一個關於如何使用可比對象的例子(注意空格也處理):

public static void main(String[] args) { 
     String[] inputs = new String[] { 
       "PIT ", 
       "  Finals 1 ", 
       "PREDICTIONS ", 
      " Match 2 ", 
      " Quarters 1 Match 1 ", 
      " Quarters 1 Match 2 ",   
      " Match 1 ", 
     "  Semis 1 Match 1 ", 
     "  Semis 2 Match 1", 
     "  Finals 2", 
     " Quarters 2 Match 1 "}; 

     List<MatchDescription> c = new ArrayList<>(); 
     for (String input : inputs) { 
      c.add(new MatchDescription(input)); 
     } 
     Collections.sort(c); 

     for (MatchDescription e : c) { 
      System.out.println(e); 
     } 

    } 
} 
+0

謝謝,這真是一個非常好的答案。標記爲正確回答和upvoted! – techguy9984

0

第一件事:給定的代碼確實包含重複的代碼。這本身就是一件壞事。但也是一個小小的表現。

示例:您正在調用parseInt(令牌[0]),類似5次或更多次。您可以重構整個方法,使其更容易閱讀,並且B)僅計算一次該表達式。

1

首先,我不說這個諷刺的,如果你要編寫代碼如getMatchScore,你應該花更多的時間學習如何編寫乾淨的代碼,而不是實際提取更多的代碼。該方法的cyclomatic complexity是屋頂。也就是說,如果我們認識到您的輸入具有固有權重的組,例如Match < Quarters,我們應該使用Enum在代碼中捕獲該數據。一個具有整數權重的簡單函數就足夠了,不需要像「Java Guy next door」所示的那樣複雜。下面的代碼,我已經測試過的工作如何?

private static final Comparator<String> BY_GROUP = (s1, s2) -> { 
    Map.Entry<Integer, Integer> e1 = toTuple(s1); 
    Map.Entry<Integer, Integer> e2 = toTuple(s2); 

    Comparator<Map.Entry<Integer, Integer>> c = Comparator.<Map.Entry<Integer, Integer>, Integer>comparing(Map.Entry::getKey) 
      .thenComparing(Map.Entry::getValue); 

    return c.compare(e1, e2); 
}; 

private static Map.Entry<Integer, Integer> toTuple(String s) { 
    String[] tokens = s.toUpperCase().split("\\s"); 
    Group group = Group.valueOf(tokens[0]); 
    int num = tokens.length > 1 ? Integer.valueOf(tokens[1]) : Integer.MIN_VALUE; 

    return new AbstractMap.SimpleImmutableEntry<>(group.weightage(), num); 
} 

private enum Group { 
    PIT(0), PREDICTIONS(1), MATCH(2), QUARTERS(3), SEMIS(4), FINALS(5); 

    private int weightage; 

    Group(int weightage) { 
     this.weightage = weightage; 
    } 

    public int weightage() { 
     return this.weightage; 
    } 
} 

public static void main(String[] args) { 
    List<String> input = Arrays.asList("PIT", "PREDICTIONS", "Match 1", "Match 2", 
      "Quarters 1 Match 1", "Quarters 1 Match 2", "Quarters 2 Match 1", "Semis 1", "Semis 2", 
      "Finals 1", "Finals 2"); 

    input.sort(BY_GROUP); 
    System.out.println(input); 
} 
+0

謝謝!我一定會試一試。我確實認識到這種方法是sh **,但我不知道如何解決它。感謝您的意見 – wdavies973