Java 如何按相反顺序对IntStream进行排序
我正在使用Java 如何按相反顺序对IntStream进行排序,java,java-8,java-stream,Java,Java 8,Java Stream,我正在使用BufferedReader从.txt文件中读取数字。我想颠倒这个蒸汽中元素的顺序,这样当它们被收集时,它们将从最高到最低排列。我不想在数组构建之后进行排序,因为我不知道其中可能包含多少元素,我只需要最高的N个元素 in = new BufferedReader(reader); int[] arr = in.lines() .mapToInt(Integer::parseInt)
BufferedReader
从.txt文件中读取数字。我想颠倒这个蒸汽中元素的顺序,这样当它们被收集时,它们将从最高到最低排列。我不想在数组构建之后进行排序,因为我不知道其中可能包含多少元素,我只需要最高的N个元素
in = new BufferedReader(reader);
int[] arr = in.lines()
.mapToInt(Integer::parseInt)
.sorted()
.limit((long) N)
.toArray();
由于反向顺序不是自然顺序,
sorted()
不能用于反向顺序排序。如果避免使用IntStream
,而是使用Stream
,则可以使用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();
int[]arr=in.lines()
.map(Integer::valueOf)//提取整数,而不是int
.sorted(Collections.reverseOrder())//在流中
.限制(N)
.mapToInt(i->i)//将整数映射到int
.toArray();
很难说.sorted().limit((long)N).toArray()
在某些情况下是否会得到优化(它依赖于实现,但我不希望看到Oracle当前的实现),但在这种特殊情况下,源流是一个大小未知的流,这使得优化的可能性更小
如果您想安全起见,您可以适应高效地获得n个最大流数。您所要做的就是颠倒顺序:
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);
});
}
但不需要创建数组,因为可以对结果使用任意
IntStream
操作。此解决方案最多只能保存N
个值,如果存在重复值,则保存的值会更少,因为它只保存不同的值及其计数。尝试在排序前对值求反,然后在排序后对值求反(返回正常值):
in = new BufferedReader(reader);
int[] arr = in.lines()
.mapToInt(Integer::parseInt)
.map(i -> -i).sorted().map(i -> -i)
.limit((long) N)
.toArray();
使用Instream时,您实际上是在处理primitive,而且您的手很紧(您仅限于自然排序,无法定义自定义比较器。您有两种解决方案:
- 坚持原始流,想出@normanrz提出的方法
- 或者,您可以转换为整数(box)并使用各种解决方案,如下面的一个解决方案(但请注意,这种装箱和取消装箱可能会导致性能问题)
Integer.MIN\u值
值,您可以添加一个步骤来映射i->(-i)
(Integer.MIN\u值
限定非常重要,因为Integer.MIN\u值==(-Integer.MIN\u值)
)。另外,您知道排序限制组合是否已优化吗?因为如果未优化,则很有可能sorted()
无论如何都要将它们存储在内存中,在这种情况下,您最好获取该数组并读取N个最大元素。@yshavit我认为您对排序限制组合的看法是正确的,它必须将其存储在某个中间容器中。它肯定必须将其存储在某个容器中。问题是,排序步骤是否足够聪明,可以知道在它后面有一个限制步骤?如果是这样,容器可能只有N个大的元素,每个新元素要么被删除,要么被推出一个以前存在的元素。如果流真的那么聪明,那么就做一些聪明的事情(就像你要求做的那样)可能绝对值得。如果不值得,那么你就不会真正节省太多。我认为I->I
可能是Integer::intValue
,对吗?@yshavit是的,Integer::intValue
可以替换那里的I->I
。很酷的技巧,尽管如果输入包含Integer.MIN\u VALUE
@TagirValeev,你不能然后切换到.map(i->~i)
而不是.map(i->-i)
@OlivierGrégoire,是的,我知道。我差不多一年前就用过这个技巧了。
in = new BufferedReader(reader);
int[] arr = in.lines()
.mapToInt(Integer::parseInt)
.map(i -> -i).sorted().map(i -> -i)
.limit((long) N)
.toArray();
int[] sortedArray = IntStream.of(costs).boxed()
.sorted(Collections.reverseOrder())
.mapToInt(value -> value.intValue()).toArray();