有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java如何按相反顺序对IntStream进行排序

我在读一本书的数字。使用BufferedReader的txt文件。我想颠倒这个蒸汽中元素的顺序,这样当它们被收集时,它们将从最高到最低排列。我不想在数组构建之后进行排序,因为我不知道其中可能包含多少元素,我只需要最高的N个元素

in = new BufferedReader(reader);
                int[] arr = in.lines()
                        .mapToInt(Integer::parseInt)
                        .sorted()
                        .limit((long) N)
                        .toArray();

共 (4) 个答案

  1. # 1 楼答案

    因为逆序不是自然顺序,sorted()不能用于逆序排序。如果避免使用IntStream,而是使用Stream<Integer>,那么可以使用Collections.reverseOrder()以与自然顺序相反的顺序对流进行排序。然后你可以调用mapToInt,最后转换成int[]

    int[] arr = in.lines()
                .map(Integer::valueOf)  // Extract Integer, not int
                .sorted(Collections.reverseOrder())  // On Stream<Integer>
                .limit(N)
                .mapToInt(i -> i)       // map Integer to int
                .toArray();
    
  2. # 2 楼答案

    尝试在排序前求反,在排序后求反(返回正常值):

    in = new BufferedReader(reader);
    int[] arr = in.lines()
                  .mapToInt(Integer::parseInt)
                  .map(i -> -i).sorted().map(i -> -i)
                  .limit((long) N)
                  .toArray();
    
  3. # 3 楼答案

    很难说.sorted().limit((long) N).toArray()在某些情况下是否会得到优化(这取决于实现,但考虑到Oracle当前的实现,我不认为会得到优化),但在这种特殊情况下,源流是一个大小未知的流,这使得优化的可能性更小

    如果你想安全起见,你可以调整this solution来有效地获得流的最大数量。你所要做的就是颠倒顺序:

    public static IntStream maxValuesDescending(IntStream source, int limit) {
        TreeMap<Integer,Integer> m=new TreeMap<>(Comparator.reverseOrder());
        source.forEachOrdered(new IntConsumer() {
            int size, min=Integer.MIN_VALUE;
            public void accept(int value) {
                if(value<min) return;
                m.merge(value, 1, Integer::sum);
                if(size<limit) size++;
                else m.compute(min=m.lastKey(), (k,count)->count==1? null: count-1);
            }
        });
        if(m.size()==limit)// no duplicates
            return m.keySet().stream().mapToInt(Integer::valueOf);
        return m.entrySet().stream().flatMapToInt(e->{
            int value = e.getKey(), count = e.getValue();
            return count==1? IntStream.of(value): IntStream.range(0, count).map(i->value);
        });
    }
    

    然后你可以像这样使用它

    int[] arr = maxValuesDescending(in.lines().mapToInt(Integer::parseInt), N).toArray();
    

    但是不需要创建数组,因为可以对结果使用任意IntStream操作。此解决方案最多可保存N个值,如果存在重复项,则保存的值更少,因为它只保存不同的值及其计数

  4. # 4 楼答案

    在使用Instream时,您实际上是在处理primitive,而且您的手很紧(您仅限于自然排序,无法定义自定义比较器。您有两种解决方案:

    • 坚持使用原始流,想出@normanrz提出的方法

    • 或者,您可以转换为整数(box)并使用各种解决方案,如下面的解决方案(但请注意,这种装箱和拆箱可能会导致性能问题)

      int[] sortedArray = IntStream.of(costs).boxed()
                                    .sorted(Collections.reverseOrder())
                                    .mapToInt(value -> value.intValue()).toArray();