簡體   English   中英

按特定順序對數據進行排序

[英]sorting data in specific order

這是我的rowId如下

1個

1.1

1.2

1.9

2

2.1

3。 9

9.9

10

10.1

List<MyBean> sortedList = rootItems.stream().sorted(Comparator.comparing(MyBean::getRowId)) .collect(Collectors.toList());

通過使用上面的代碼,我得到如下的輸出。

1個

10

11

12

2

2.1

2.2

但我想要像下面的輸出

1個

1.1

1.1.1

1.1.1.1

1.2

1.3

1.9

10

11

2

2.1

2.2

2.3

3

3.1

3.2

4

9

9.1

9.2

9.9

10

10.1

像這樣它需要繼續

如果我想要這樣,我需要使用哪一套

我沒有在計算機上嘗試過,但是為了進行比較,似乎數據沒有轉換為兩倍。 我認為在排序之前添加mapToDouble(i->i.getRowId)將解決您的問題。

使用自己的compare()方法,如下所示:

Collections.sort(myList, new Comparator<String>() {
    @Override
    public int compare(String id1, String id2) {
        double d1 = Double.parseDouble(id1);
        double d2 = Double.parseDouble(id2);
        return Double.compare(d1, d2);
    }
});

或僅將ID解析/映射為double,然后對其進行比較/排序。

正如我在評論中已經提到的那樣,問題在於字符串是在逐個字符的基礎上進行比較的。 因此,您將需要更改字符串以使每個元素具有相等的長度,並且每個字符位置都與其他id中的相同位置相對應,或者將這些元素解析為數字序列

備選方案1的缺點是,每個組件都需要具有固定的最大長度(即abc a,b,c等),或者必須首先計算元素數。

因此,替代方法2似乎更好,但是每次比較字符串時都解析字符串可能會花費一些錢。 因此,您可能想要引入一個代表您的id的類,該類包含實際的id字符串以及已解析的版本。 該類可以實現Comparable並且只能在已解析的版本上運行。

例:

class MyRowId implements Comparable<MyRowId> {
  private final String id;

  //when serializing instances of that class you might want to ignore this array 
  //and upon deserialization parse the string again
  private final int[] parsed;

  public MyRowId( String idString ) {
    id = idString;
    parsed = Arrays.stream( idString.split("\\.") ).mapToInt( Integer::parseInt ).toArray();
  }

  public int compareTo( MyRowId other )  {
    //Compare the elements one by one until we run out of elements or hit a difference
    //There might be a more Java8-ish way but I didn't find it yet
    for( int i = 0; i < Math.min( parsed.length, other.parsed.length ); i++ ) {
      int r = Integer.compare( parsed[i], other.parsed[i] );
      if( r != 0 ) {
        return r;
      }
    }

    //If we're here all compared elements were equal but one id might be longer so compare the lengths.
    //That would handle things like comparing "1.1" to "1.1.1" where the latter is greater.
    return Integer.compare( parsed.length, other.parsed.length );
  }
}

如果在內部對這些字符串進行標准化,然后將其排序,則比較這些字符串會容易得多。 我建議用零填充單個項目,如下所示:

private static final Pattern SINGLE_DIGIT = Pattern.compile("\\b(\\d)\\b");
...
String padWithZeroes = SINGLE_DIGIT.matcher(yourInputString).replaceAll("0$1");

現在只需對填充字符串進行排序。 假設最高數字為2位數字,否則,我們需要調整正則表達式,並且邏輯會稍微復雜一些。


如果任何數字段的長度可以大於2位,那么它將變得更加復雜。 這是一種將所有段填充到最大長度的方法:

static String padWithZeroes(String yourInputString, int digits) {
    final Matcher matcher = SINGLE_DIGIT.matcher(yourInputString);
    StringBuffer sb = new StringBuffer();
    while(matcher.find()){

        matcher.appendReplacement(sb, pad(digits - matcher.group().length())+matcher.group());
    }
    matcher.appendTail(sb);
    return sb.toString();
}

static String pad(int length) {
    final char[] chars = new char[length];
    Arrays.fill(chars, '0');
    return new String(chars);
}

這里的問題是,您必須預先知道digits參數的值,因此您要么知道數據,要么必須進行單獨的迭代以測量最大長度。

如果指定了getRowId()的返回類型,則實現可能會有所不同。


您可能要做的是為MyBean類定義一個Comparator。 可以實現為

  • 匿名班
  • lambda表達式。

在您的情況下,可能是:

class MyBeanComparator implements Comparator<MyBean>{
  public static final MyBeanComparator INSTANCE = new MyBeanComparator();
  public int compare(MyBean b1, MyBean b2){
         //your custom rules
      }
}

然后

List<MyBean> sortedList = rootItems.stream().sorted(MyBeanComparator.INSTANCE::compare) .collect(Collectors.toList());

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM