[英]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。 可以實現為
在您的情況下,可能是:
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.