简体   繁体   English

带定界值的排序数组

[英]Sorting array with delimited values

I have an array with values of format 'int.int.int' 我有一个值格式为'int.int.int'的数组

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

I want so sort this array by first number, then result of first sorting sort by second number still keeping array sorted by first value and the same thing with third number. 我想按第一个数字排序此数组,然后按第二个数字排序的第一个结果仍然保持数组按第一个值排序和与第三个数字相同。 Expected result: 预期结果:

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

The simplest solution is to create auxiliary arrays and use for loops, but I am wondering if it is possible to do it simpler. 最简单的解决方案是创建辅助数组并用于循环,但是我想知道是否有可能使它更简单。 I've also tried to use groovy sorting 我也尝试使用groovy排序

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

where I've removed delimiters and sorted elements like they were integers, but it didn't work for example for such a values 我删除了定界符并对元素进行了排序,就像它们是整数一样,但是对于这样的值它是行不通的

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

The output was 输出是

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

Any ideas how to sort it in simple way, not by creating new arrays and iterating 3 times by original array? 有什么想法如何以简单的方式对其进行排序,而不是通过创建新数组并通过原始数组进行3次迭代来进行排序?

Write a custom Comparator that split() s around . 编写一个自定义的Comparator ,它围绕split() That will give you a String[] . 那会给你一个String[] Turn the first values of the two arrays into ints and compare them. 将两个数组的第一个值转换为int并进行比较。 If they're equal, turn the second two values into ints and compare, etc. If all three pairs of ints are equal, then the values are equal. 如果它们相等,则将后两个值转换为int并进行比较,依此类推。如果所有三对int均相等,则值相等。

You could do this: 可以这样做:

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

Or (arguably neater) 或(可以说更整洁)

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

Or, if version numbers can be different numbers of integers (ie: 1.6 , 1.7.43.3 ): 或者,如果版本号可以是整数的不同的数字(即: 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()
    }
}

Or use a custom comparator ;-) 或使用自定义比较器;-)

Use the Arrays.sort(....) method, and give it a Comparator that has the following compare(String a, String b) method: 使用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;
}

If you want to have as little temporary object creation as possible you have to implement the parsing inside the comparator yourself. 如果要尽可能少地创建临时对象,则必须自己在比较器内部实现解析。

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

Then you can say, for example: 然后您可以说,例如:

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

However for large datasets it can be still the case that converting to a pre-parsed representation before sorting (and converting back afterwards) is faster than on-the-fly parsing inside the comparator. 但是,对于大型数据集,在排序之前转换为预先解析的表示(然后再转换回)仍然比在比较器内部进行即时解析要快。

The idea is to convert each string to tuple of integers (let's name it NumberInfo , for example), ie "100.2.0" => { 100, 2, 0 }, because the integer representation is useful to perform comparison (comparison is used to sort items). 想法是将每个字符串转换为整数元组(例如,将其命名为NumberInfo ),即“ 100.2.0” => {100,2,0},因为整数表示形式对执行比较很有用(使用比较)对项目进行排序)。

So, after conversion of List<String> to List<NumberInfo> , the List<NumberInfo> can be sorted. 因此,在将List<String>转换为List<NumberInfo> ,可以对List<NumberInfo>进行排序。

"Tuple": “元组”:

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

Tuple comparator: 元组比较器:

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

Main method: 主要方法:

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