3

我想做一个特定的排序。我正在使用 java 的可比较接口,这意味着我的比较方法的返回必须返回 -1 +1 或 0,具体取决于两个比较的相等性,然后我使用 Collections 进行排序。我的麻烦来自于我希望如何比较。

我有一个由以下任一组成的密钥

[keyName]  
[siteName].[keyName]  
[siteName].[pageName].[keyName]  

以“mysite.alampshade.color”为例

棘手的部分是必须首先对站点进行排序,然后是 keyname,然后是 pageName。但首先是键名,然后是站点名称,按照属性部分的数量顺序排列。对不起。它有点复杂,一个例子可能会有所帮助。这是它们必须的顺序:

alpha  
beta  
charlie  
sitea.alpha  
sitea.charlie  
sitea.pagea.beta  
sitea.pageb.beta  
sitea.pagea.charlie  
siteb.alpha  
siteb.delta  
siteb.pagef.alpha  
siteb.pageb.echo  
siteb.pageb.golf  
siteb.pagea.hotel  
siteb.pageb.hotel  
siteb.pagec.hotel  

我尝试了许多不同的方法,并且已经扔掉了几次代码,但仍然无法使其完美。如果不是一些java,一些伪代码会很有帮助。

编辑:添加另一个可能更容易理解的示例,以下是我需要的排序方式

a  
b  
c  
z  
a.b  
a.c  
a.d  
a.z  
a.b.a  
a.c.a  
a.b.b  
a.b.c  
a.c.c  
a.a.d  
b.a  
b.b  
b.z  
b.a.a  
b.b.a  
b.a.b  
c.c.f  
4

4 回答 4

2

现在应该好了。

public int compare(String a, String b) {
String[] partsA = a.split("\\.");
String[] partsB = b.split("\\.");

// If first term is different, we exit.
if (partsA[0].compareTo(partsB[0]) != 0) return partsA[0].compareTo(partsB[0]);

// Else, first term is identical.
else {
    // Same number of parts
    if (partsA.length == partsB.length) {
        // 2 parts, we compare the 2nd part.
        if (partsA.length == 2) {
            return partsA[1].compareTo(partsB[1]);
        // 3 parts, we compare the 3rd part first, then the 2nd part        
        } else {
            if (partsA[2].compareTo(partsB[2]) != 0) return partsA[2].compareTo(partsB[2]);
            return partsA[1].compareTo(partsB[1]);
        }

    // Different number of parts
    } else {
        // If A has only 1 part, it's first
        if (partsA.length == 1) return -1;
        // If B has only 1 part, it's first
        if (partsB.length == 1) return 1;

        // Case 2 vs 3 parts, we compare the 3rd part with the 2nd part of the other. If it's equal, the shorter is first.
        if (partsA.length == 3) {
            if (partsA[2].compareTo(partsB[1]) != 0) return partsA[2].compareTo(partsB[1]);
            else return 1;
        } else {
            if (partsA[1].compareTo(partsB[2]) != 0) return partsA[1].compareTo(partsB[2]);
            else return -1;
        }           
    }
}
}
于 2013-03-21T14:15:34.077 回答
2

另一种选择,使其递归,如果有更多条目,您可以避免问题。

import java.util.ArrayList; import java.util.Arrays; import java.util.Comparator; import java.util.List;

public class SortTest {
    public static void main(String[] args) {
        String[] test = new String[]{
            "a",
            "b",
            "b.a",
            "b.a.a",
            "a.a.a",
            "a.b.a",
            "a.a",
            "a.b",
            "b.a.b",
            "b.b.a"
        };

        Arrays.sort(test, new Comparator<String>() {

        int compareComplexList(List<String> a, List<String> b, List<int[]> positions, int order ) {

          int minimum = a.size() < b.size() ? a.size() - 1 : b.size() - 1;   

          if (a.get(positions.get(minimum)[order]).compareTo(b.get(positions.get(minimum)[order])) != 0)
                return a.get(positions.get(minimum)[order]).compareTo(b.get(positions.get(minimum)[order]));
          else if (order < minimum - 1) return compareComplexList(a,b, positions, ++order);
          else return Double.compare(a.size(),b.size());
        }

        public int compare(String a, String b) {
          List<String> partsA = Arrays.asList(a.split("\\."));
          List<String> partsB = Arrays.asList(b.split("\\."));
          List<int[]>  orders = new ArrayList<int[]>();

          orders.add(new int[] {0});
          orders.add(new int[] {0,1});
          orders.add(new int[] {0,2,1});

          return compareComplexList(partsA, partsB, orders,0);
        }
        });
        System.out.println("Sorted: "+Arrays.toString(test));
    }

}
于 2013-03-21T16:44:50.197 回答
1

My other answer started getting too gnarly. Here's a better, more natural solution:

public class StrangeComparator {
  private static class Entry implements Comparable<Entry> {
    // What to split with.
    static final String dot = Pattern.quote(".");
    // The parts.
    final String key;
    final String page;
    final String site;

    public Entry(String s) {
      String [] parts = s.split(dot);
      switch (parts.length) {
        case 1:
          key = parts[0];
          page = "";
          site = "";
          break;

        case 2:
          key = parts[1];
          page = "";
          site = parts[0];
          break;

        case 3:
          key = parts[2];
          page = parts[1];
          site = parts[0];
          break;

        default:
          throw new IllegalArgumentException("There must be at least one part to an entry.");
      }
    }

    @Override
    public int compareTo(Entry t) {
      int diff = site.compareTo(t.site);
      if ( diff == 0 ) {
        diff = page.compareTo(t.page);
      }
      if ( diff == 0 ) {
        diff = key.compareTo(t.key);
      }
      return diff;
    }

    @Override
    public String toString () {
      return (site.length() > 0 ? site + "." : "")
              + (page.length() > 0 ? page + "." : "")
              + key;
    }
  }

  public void test() {
    String[] test = new String[]{
      "alpha",
      "beta",
      "charlie",
      "zeta", // Added to demonstrate correctness.
      "sitea.alpha",
      "sitea.charlie",
      "sitea.pagea.beta",
      "sitea.pageb.beta",
      "sitea.pagea.charlie",
      "siteb.alpha",
      "siteb.delta",
      "siteb.pagef.alpha",
      "siteb.pageb.echo",
      "siteb.pageb.golf",
      "siteb.pagea.hotel",
      "siteb.pageb.hotel",
      "siteb.pagec.hotel"
    };
    Arrays.sort(test);
    System.out.println("Normal sort: " + Separator.separate("\n", "\n", test));
    Entry[] entries = new Entry[test.length];
    for ( int i = 0; i < test.length; i++ ) {
      entries[i] = new Entry(test[i]);
    }
    Arrays.sort(entries);
    System.out.println("Special sort: " + Separator.separate("\n", "\n", entries));
  }

  public static void main(String args[]) {
    new StrangeComparator().test();
  }
}

Output order is:

alpha
beta
charlie
zeta
sitea.alpha
sitea.charlie
sitea.pagea.beta
sitea.pagea.charlie
sitea.pageb.beta
siteb.alpha
siteb.delta
siteb.pagea.hotel
siteb.pageb.echo
siteb.pageb.golf
siteb.pageb.hotel
siteb.pagec.hotel
siteb.pagef.alpha

Which kinda does what you say but doesn't match your example.

于 2013-03-21T17:07:47.177 回答
0

这是另一种选择 - 如果发现一个组件包含少于 3 个零件,则在开始时添加零件以填补空缺。然后它使用排序顺序数组来定义接下来应该比较哪些列:

  public void test() {
    String[] test = new String[]{
      "alpha",
      "beta",
      "charlie",
      "zeta", // Added to demonstrate correctness.
      "sitea.alpha",
      "sitea.charlie",
      "sitea.pagea.beta",
      "sitea.pageb.beta",
      "sitea.pagea.charlie",
      "siteb.alpha",
      "siteb.delta",
      "siteb.pagef.alpha",
      "siteb.pageb.echo",
      "siteb.pageb.golf",
      "siteb.pagea.hotel",
      "siteb.pageb.hotel",
      "siteb.pagec.hotel"
    };
    Arrays.sort(test);
    System.out.println("Normal sort: "+Arrays.toString(test));
    Arrays.sort(test, new Comparator<String>() {
      // How many columns to pad to.
      final int padTo = 3;
      // What to pad with.
      final String padWith = "";
      // What order to compare the resultant columns in.
      final int[] order = {0, 2, 1};

      @Override
      public int compare(String s1, String s2) {
        String[] s1parts = padArray(s1.split(Pattern.quote(".")), padTo, padWith);
        String[] s2parts = padArray(s2.split(Pattern.quote(".")), padTo, padWith);
        int diff = 0;
        for ( int i = 0; diff == 0 && i < order.length; i++ ) {
          diff = s1parts[order[i]].compareTo(s2parts[order[i]]);
        }
        return diff;
      }

      String [] padArray(String[] array, int padTo, String padWith) {
        String [] padded = new String[padTo];
        for ( int i = 0; i < padded.length; i++ ) {
          padded[padded.length - i - 1] = i < array.length ? array[i]: padWith;
        }
        return padded;
      }
    });
    System.out.println("Special sort: "+Arrays.toString(test));
  }

打印(或多或少):

Normal sort: [alpha,
 beta,
 charlie,
 sitea.alpha,
 sitea.charlie,
 sitea.pagea.beta,
 sitea.pagea.charlie,
 sitea.pageb.beta,
 siteb.alpha,
 siteb.delta,
 siteb.pagea.hotel,
 siteb.pageb.echo,
 siteb.pageb.golf,
 siteb.pageb.hotel,
 siteb.pagec.hotel,
 siteb.pagef.alpha,
 zeta]
Special sort: [alpha,
 beta,
 charlie,
 sitea.alpha,
 sitea.charlie,
 siteb.alpha,
 siteb.delta,
 zeta,
 siteb.pagef.alpha,
 sitea.pagea.beta,
 sitea.pageb.beta,
 sitea.pagea.charlie,
 siteb.pageb.echo,
 siteb.pageb.golf,
 siteb.pagea.hotel,
 siteb.pageb.hotel,
 siteb.pagec.hotel]

您的要求似乎有些模棱两可,但这段代码是结构化的,因此您可以通过微不足道的调整,非常简单地实现对比较的大多数解释。

于 2013-03-21T14:39:17.597 回答