1

我有一个格式为“int.int.int”的数组

String[] tab = [ '100.2.0' , '5.7.4' , '7.6.1' , '5.6.4' ]

我想按第一个数字对该数组进行排序,然后按第二个数字进行第一次排序的结果仍然保持数组按第一个值排序,并且与第三个数字相同。预期结果:

['5.6.4','5.7.4','7.6.1','100.2.0']

最简单的解决方案是创建辅助数组并使用 for 循环,但我想知道是否可以更简单地做到这一点。我也尝试过使用常规排序

tab.sort { it -~ /\./ }

我已经删除了分隔符和排序元素,就像它们是整数一样,但是对于这样的值它不起作用

[ '2.12.1' , '10.5.2' , '5.2.3' ]

输出是

[ '5.2.3' , '10.5.2' , '2.12.1' ]

任何想法如何以简单的方式对其进行排序,而不是通过创建新数组并通过原始数组迭代 3 次?

4

5 回答 5

0

这个想法是将每个字符串转换为整数元组(NumberInfo例如,我们将其命名),即“100.2.0”=> { 100, 2, 0 },因为整数表示对于执行比较很有用(比较用于排序项目)。

因此,在转换为 之后List<String>List<NumberInfo>可以List<NumberInfo>对 进行排序。

“元组”:

class NumberInfo {
    private int a;
    private int b;
    private int c;

    private NumberInfo(int a, int b, int c) {
        this.a = a;
        this.b = b;
        this.c = c;
    }

    int getA() {
        return a;
    }

    int getB() {
        return b;
    }

    int getC() {
        return c;
    }

    public static NumberInfo fromString(String s) {
        String[] itemComponents = s.split("[.]");
        if (itemComponents.length != 3) {
            throw new IllegalArgumentException("Three comma delimited components expected");
        }

        int a = Integer.parseInt(itemComponents[0]);
        int b = Integer.parseInt(itemComponents[1]);
        int c = Integer.parseInt(itemComponents[2]);

        NumberInfo numberInfo = new NumberInfo(a, b, c);
        return numberInfo;
    }

    @Override
    public String toString() {
        return a + "." + b + "." + c;
    }
}

元组比较器:

class NumberInfoComparator implements Comparator<NumberInfo> {
    @Override
    public int compare(NumberInfo o1, NumberInfo o2) {
        int result = Integer.compare(o1.getA(), o2.getA());
        if (result != 0)
            return result;

        result = Integer.compare(o1.getB(), o2.getB());
        if (result != 0) {
            return result;
        }

        result = Integer.compare(o1.getC(), o2.getC());
        return result;
    }
}

主要方法:

public static void main(String[] args) {
    String[] tab = { "100.2.0" , "5.7.4" , "7.6.1" , "5.6.4" };

    ArrayList<NumberInfo> numberInfoList = new ArrayList<NumberInfo>();
    for (String item : tab) {
        NumberInfo numberInfo = NumberInfo.fromString(item);
        numberInfoList.add(numberInfo);
    }

    NumberInfoComparator numberInfoComparator = new NumberInfoComparator();
    Collections.sort(numberInfoList, numberInfoComparator);

    for (NumberInfo numberInfo : numberInfoList) {
        System.out.println(numberInfo);
    }
}
于 2013-09-18T12:50:03.980 回答
0

写一个风俗习惯Comparatorsplit()那会给你一个String[]. 将两个数组的第一个值转换为整数并进行比较。如果它们相等,则将后两个值转换为整数并进行比较,等等。如果所有三对整数都相等,则值相等。

于 2013-09-18T12:00:14.633 回答
0

可以这样做:

tab.sort { a, b -> [ a, b ]*.tokenize( '.' )*.
                           collect { it.toInteger() }
                           .transpose()
                           .findResult { x, y -> x <=> y ?: null } }

或者(可以说更整洁)

tab.sort { a, b ->
    [ a, b ]*.tokenize( '.' )
             .transpose()
             .findResult { x, y ->
                  x.toInteger() <=> y.toInteger() ?: null
              }
}

或者,如果版本号可以是不同数量的整数(即:1.6、、1.7.43.3):

tab.sort { a, b ->
    [ a, b ]*.tokenize( '.' ).with { u, v ->
        [ u, v ].transpose().findResult { x, y ->
             x.toInteger() <=> y.toInteger() ?: null
        } ?: u.size() <=> v.size()
    }
}

或使用自定义比较器;-)

于 2013-09-18T12:07:15.427 回答
0

使用Arrays.sort(....)方法,并给它一个Comparator具有以下 compare(String a, String b) 方法:

public int compare (String a, String b) {
    String[] avals = a.split("\\.");
    String[] bvals = b.split("\\.");
    for (int i = 0; i < avals.length; a++) {
        int diff = Integer.parseInt(bvals[i]) - Integer.parseInt(avals[i]);
        if (diff != 0) {
            return diff;
        }
    }
    return 0;
}
于 2013-09-18T12:08:50.093 回答
0

如果您希望尽可能少地创建临时对象,则必须自己在比较器中实现解析。

public static final class XComparator implements Comparator<String>
{
  public static final Comparator<String> INSTANCE = new XComparator();
  private XComparator(){}

  public int compare(String o1, String o2)
  {
    final int l1=o1.length(), l2=o2.length();
    for(int p1=0, p2=0;; p1++, p2++)
    {
      int v1=0, v2=0;
      for(;p1<l1 && o1.charAt(p1)!='.';p1++) v1=nextChar(v1, o1.charAt(p1));
      for(;p2<l2 && o2.charAt(p2)!='.';p2++) v2=nextChar(v2, o2.charAt(p2));
      if(v1<v2) return -1; else if(v1>v2) return +1;
      if(p1==l1) return p2==l2? 0: -1;
      else if(p2==l2) return +1;
    }
  }
  private int nextChar(int v, char ch)
  {
    if(ch<'0'||ch>'9') throw new IllegalArgumentException();
    return v*10+ch-'0';
  }
}

然后你可以说,例如:

String[] tab = { "100.2.0" , "5.7.4" , "7.6.1" , "5.6.4", "5", "3.4", "7.6" };
System.out.println(Arrays.toString(tab));
Arrays.sort(tab, XComparator.INSTANCE);
System.out.println(Arrays.toString(tab));

然而,对于大型数据集,在排序之前转换为预解析表示(并在之后转换回来)仍然比比较器内的动态解析更快。

于 2013-09-18T12:27:14.543 回答