2017-07-03 65 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