繁体   English   中英

带定界值的排序数组

[英]Sorting array with delimited values

我有一个值格式为'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']

最简单的解决方案是创建辅助数组并用于循环,但是我想知道是否有可能使它更简单。 我也尝试使用groovy排序

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

我删除了定界符并对元素进行了排序,就像它们是整数一样,但是对于这样的值它是行不通的

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

输出是

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

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

编写一个自定义的Comparator ,它围绕split() 那会给你一个String[] 将两个数组的第一个值转换为int并进行比较。 如果它们相等,则将后两个值转换为int并进行比较,依此类推。如果所有三对int均相等,则值相等。

可以这样做:

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.61.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()
    }
}

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

使用Arrays.sort(....)方法,并为它提供一个具有以下compare(String a,String b)方法的Comparator

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

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

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

但是,对于大型数据集,在排序之前转换为预先解析的表示(然后再转换回)仍然比在比较器内部进行即时解析要快。

想法是将每个字符串转换为整数元组(例如,将其命名为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);
    }
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM