按特定顺序排序数据

时间:2017-12-20 12:14:28

标签: java collections set

这里我的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

     

     

像这样需要继续

如果我想要这样哪个Set我需要使用

5 个答案:

答案 0 :(得分:0)

我没有在我的计算机上尝试过,但似乎数据没有翻译成双倍的比较。我认为在排序之前添加mapToDouble(i->i.getRowId)可以解决您的问题。

答案 1 :(得分:0)

使用自己的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);
    }
});

或者只是解析/ map将ID转换为double并对其进行比较/排序。

答案 2 :(得分:0)

正如我在评论中所述,问题是字符串是逐个字符进行比较的。因此,您需要更改字符串,以便每个元素具有相等的长度,并且每个字符位置对应于其他ID中的相同位置,或者将元素解析为数字序列

备选方案1的缺点是,您需要为每个组件设置固定的最大长度(即a.b.c中的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 );
  }
}

答案 3 :(得分:0)

如果您在内部将它们标准化,那么比较这些字符串会更容易,然后可以对其进行排序。我建议用零填充单个项目,如下所示:

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参数的值,所以要么你知道你的数据,要么你必须做一个单独的迭代来测量最大长度。

答案 4 :(得分:-2)

如果您指定了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());