先对整数列表排序,然后在 java 8 中按被 10 整除排序

Sort the integer list first and then sort by divisible by 10 in java 8

我有包含 {3,10,17,9,20,15,40,30, 55} 的数组列表,所以我想对这个方法进行排序,以便所有可被 10 整除的值排在排序列表的最后在排序列表之后。 即 o/p 应该是这样的:{3, 9, 15, 17, 55, 10, 20, 30, 40}

我已尝试使用以下代码,但无法成功整理出此列表,

List<Integer> list = Arrays.asList(3,10,17,9,20,55,40,30);

list.stream().sorted(((Comparator<Integer>) (v1, v2) -> Integer.compare(v1, v2))).sorted((Comparator<Integer>) (v1, v2) -> v1 % 10 == 0 ? 0 : -1).forEach(System.out::println);

以上代码的输出是: 55 17 9 3个 10 20 30 40

谢谢,

您似乎想从逻辑上将数字分成两组,然后分别对每组进行排序。

您可以根据除以 10 的标准拆分列表,然后分别对 2 个子列表进行排序,或者您可以使用单个 Comparator 检查是否2个比较数字属于同一组:

  • 如果他们不这样做,则根据组确定哪个应该排在第一位
  • 如果他们这样做,请按他们的价值在他们的组内比较他们

    list.stream()
        .sorted((v1, v2) -> {
                    if (v1 % 10 == 0) {
                        if (v2 % 10 == 0)
                            return Integer.compare(v1, v2); // both are divisible by 10 
                                                            // sort by value
                        else
                            return 1; // only v1 is divisible by 10, should come after v2
                    } else {
                        if (v2 % 10 != 0)
                            return Integer.compare(v1, v2); // both are not divisible by 10
                                                            // sort by value
                        else
                            return -1; // only v2 is divisible by 10, should come after v1
                    }
    
            })
        .forEach(System.out::println);
    

输出:

3
9
17
55
10
20
30
40

要实现这一点,您需要:

  • 首先把列表分成两个列表,一个是数字能被整除的列表 10 第二个是那些不是的人。
  • 那就单独排序吧
  • 最后将第一个附加到第二个。

你的代码应该是这样的:

List<Integer> dividedBy10 = list.stream()
    .filter(p -> p % 10 == 0).collect(Collectors.toList());
Collections.sort(dividedBy10);

List<Integer> others = list.stream()
    .filter(p -> p % 10 != 0).collect(Collectors.toList());
Collections.sort(others);

//Then append the first list to the sorted one
others.addAll(dividedBy10);

编辑:

或者像 @yahya 建议的那样,您可以只对原始列表进行排序,然后将其过滤成列表并稍后附加这两个列表:

Collections.sort(list);

List<Integer> dividedBy10 = list.stream()
    .filter(p -> p % 10 == 0).collect(Collectors.toList());

List<Integer> others = list.stream()
    .filter(p -> p % 10 != 0).collect(Collectors.toList());
others.addAll(dividedBy10);

需要单次排序:

list.stream().sorted(((Comparator<Integer>) (v1, v2) -> {

    // if both are divisible by 10, you sort them with their order natural
    if (v1 % 10 == 0 && v2 % 10 == 0) {
       return Integer.compare(v1, v2);
    }

    // if only the first argument is divisible by 10, it is always at the end
    else if (v1 % 10 == 0) {
      return 1;
    }       

    // if only the second argument is divisible by 10, it is always at the end
    else if (v2 % 10 == 0) {
      return -1;
    }

    // in other cases, you sort by natural order
    return Integer.compare(v1, v2);
}))
    .forEach(System.out::println);

这是输出:

3 9 17 55 10 20 30 40

目前,您正在对不能被 10 整除的数字取反,作为一种黑客手段,以便首先将它们取出。但这会颠倒这些数字的顺序,这会影响您的输出!

比较被 10 整除的数字时需要更加小心,因此比较器将它们排在其他数字的后面。这样的事情会起作用:

list.stream().sorted(((Comparator<Integer>) (v1, v2) -> {
    if (v1 % 10 == 0 && v2 % 10 == 0) {
        return Integer.compare(v1, v2);
    } else if (v1 % 10 == 0) {
        // v2 is effectively larger
        return -1;
    } else if (v2 % 10 == 0) {
        // v1 is effectively larger
        return 1;
    }
    return Integer.compare(v1, v2);
}))/*etc*/
(a,b) -> (a<b?-1:a==b?0:1) + (a%10==0?2:0) - (b%10==0?2:0)

这是如何工作的:

(a<b?-1:a==b?0:1) 通常比较整数(权重为 1)

+ (a%10==0?2:0) 检查第一个整数是否能被 10 整除(权重为 2)

- (b%10==0?2:0) 检查第二个整数是否能被 10 整除(权重为 2)


只要 Integer.compare 只有 returns -1,0,1 你就可以使用这个(但是 @Holger 指出没有保证)

(a,b) -> Integer.compare(a, b) + (a%10==0?2:0) - (b%10==0?2:0)

您只有三个 return 值:

  • Integer.compare(a, b) 如果两个值都可以被 10 整除,当它们不能被 10 整除时
  • > 0 如果第一个值能被 10 整除
  • < 0 否则

list.sort((a, b) -> {
  if ((a % 10 == 0) == (b % 10 == 0)) {
    return a.compareTo(b);
  } else {
    return a % 10 == 0 ? 1 : -1;
  }
});

或者如果您更喜欢不可读的代码

list.sort((a, b) -> (a % 10 == 0) == (b % 10 == 0) ? a.compareTo(b) : a % 10 == 0 ? 1 : -1);

有两件事要知道。

首先,当您知道 Boolean 值自 Java 5 以来具有可比性时,排序时按特定谓词分组非常容易。因此您可以使用

Comparator.comparing(i -> i%10==0)

对可被 10 整除的数字排序到最后。

其次,您可以使用 thenComparing 链接比较器,这样根据第一个比较器相等的元素将根据下一个比较器排序。

一起运算就变成了

List<Integer> list = Arrays.asList(3,10,17,9,20,55,40,30);

list.stream()
    .sorted(Comparator.comparing((Integer i) -> i%10==0)
                      .thenComparing(Comparator.naturalOrder()))
    .forEach(System.out::println);

请注意,由于类型推断的限制,完整操作需要第一个 lambda 表达式 ((Integer i)) 的显式类型参数。

你也可以这样写

list.stream()
    .sorted(Comparator.comparing((Integer i) -> i%10==0)
                      .thenComparingInt(i -> i))
    .forEach(System.out::println);

不过,我更喜欢在适用时重用现有的比较器 Comparator.naturalOrder()