简体   繁体   English

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

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

I have arraylist containing {3,10,17,9,20,15,40,30, 55} so I want to sort this method so that all the divisible by 10 values are come in last in sorted list aftet the sorting the list. 我有包含{3,10,17,9,20,15,40,30,55}的arraylist所以我想对这个方法进行排序,以便在列表排序后,所有可被10个值整除的值排在最后的排序列表中。 ie o/p should be like this : {3, 9, 15, 17, 55, 10, 20, 30, 40} 即o / p应该是这样的:{3,9,15,17,55,10,20,30,40}

I have tried with below code but a I am not able to successfully sort out this list, 我试过下面的代码,但我无法成功整理这个列表,

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

output of above code is: 55 17 9 3 10 20 30 40 以上代码的输出为:55 17 9 3 10 20 30 40

Thanks, 谢谢,

It looks like you want to logically divide the numbers into two groups and sort each group separately. 看起来您希望将数字逻辑划分为两组,并分别对每组进行排序。

You can either split the list based on the division by 10 criteria, and perform the sort on the 2 sub-lists separately, or you can achieve the same result with a single Comparator that checks whether the 2 compared numbers belong to the same group: 您可以根据划分10个条件拆分列表,并分别对2个子列表执行排序,或者使用单个Comparator检查2个比较的数字是否属于同一组,可以获得相同的结果:

  • if they don't, determine which should come first based on the group 如果他们不这样做,根据小组确定哪个应该首先出现
  • if they do, compare them within their group by their value 如果他们这样做,在他们的组内比较他们的价值

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

Output: 输出:

3
9
17
55
10
20
30
40

There are two things to know. 有两件事要知道。

First, grouping by a particular predicate when sorting is quiet easy when you know that Boolean values are comparable since Java 5. So you can use 首先,当您知道自Java 5以来Boolean值具有可比性时,在排序时很容易按特定谓词进行分组。因此您可以使用

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

to sort numbers dividable by ten to the end. 将数字分类为十分之一到最后。

Second, you can chain comparators using thenComparing , so that elements being equal according to the first comparator will be sorted according to the next one. 其次,您可以使用thenComparing链接比较器,以便根据第一个比较器的元素相等将根据下一个比较器进行排序。

Together, the operation becomes 一起,操作变为

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

Note that the complete operation requires an explicitly typed parameter for the first lambda expression ( (Integer i) ) due to limitations in the type inference. 请注意,由于类型推断的限制,完整操作需要第一个lambda表达式( (Integer i) )的显式类型参数。

You could also write 你也可以写

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

though, I prefer reusing the already existing comparator Comparator.naturalOrder() when applicable. 但是,我更喜欢重用现有的比较器Comparator.naturalOrder()

Well to achieve this you need to: 要实现这一目标,您需要:

  • First divide the list into two lists, one with numbers divisible by 10 and the second with those who aren't. 首先将列表分成两个列表,一个列表可以被10整除,另一个列表可以被10个整除。
  • Then just sort them separately 然后单独对它们进行排序
  • And finally append the first to second one. 最后将第一个追加到第二个。

This is how should be your code: 这是你的代码应该如何:

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

Edit: 编辑:

Or like @yahya suggested you can just sort your original list, then filter it into lists and append these two lists later: 或者像@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);

Currently you are negating the numbers that are not divisible by 10 as a hack to get them out first. 目前你正在否定那些不能被10整除的数字作为黑客首先将它们排除在外。 But that will reverse the order of those numbers, which accounts for your output! 但这会扭转这些数字的顺序,这会影响你的输出!

You need to be more careful when comparing the divisible by 10 numbers, so the comparator ranks them lower than other numbers. 在将可整除的10个数字进行比较时需要更加小心,因此比较器将它们排在低于其他数字的位置。 Something like this will work: 这样的东西会起作用:

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 single sort is required : 需要单一种类:

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

Here is the output : 这是输出:

3 9 17 55 10 20 30 40 3 9 17 55 10 20 30 40

(a,b) -> (a<b?-1:a==b?0:1) + (a%10==0?2:0) - (b%10==0?2:0)

How this works: 这是如何工作的:

(a<b?-1:a==b?0:1) normally compares the integers (Has a weight of 1) (a<b?-1:a==b?0:1)通常比较整数(权重为1)

+ (a%10==0?2:0) Checks if the first integer is divisible by 10 (Has a weight of 2) + (a%10==0?2:0)检查第一个整数是否可被10整除(权重为2)

- (b%10==0?2:0) Checks if the second integer is divisible by 10 (Has a weight of 2) - (b%10==0?2:0)检查第二个整数是否可被10整除(权重为2)


As long as Integer.compare only returns -1,0,1 you could use this (But as @Holger points out there is no guaranty) 只要Integer.compare只返回-1,0,1就可以使用它(但是@Holger指出没有保证)

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

You only have three return values: 您只有三个返回值:

  • Integer.compare(a, b) if both values are divisible by 10 and when they are not Integer.compare(a, b)如果两个值都可以被10整除,那么它们可以被整除
  • > 0 if first value is divisible by 10 如果第一个值可被10整除,则> 0
  • < 0 else < 0其他

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

Or if you prefer non readable code 或者如果您更喜欢不可读的代码

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM