使用 Java8 流 API 从集合中删除最大值(或最小值)

问题描述 投票:0回答:3

我对使用 Java 8 中的新流 API 的代码设计没有什么问题。我想学习新东西,任务之一是:

从列表中拒绝最大值和最小值。列表不包含重复项。

看起来很简单?不...我的代码:

  List<Integer> ranges = Lists.newArrayList(new Range(1, 15));
        List<Integer> collect = ranges.stream()
                .filter(x -> x != ranges.stream()
                        .mapToInt(Integer::intValue)
                        .max()
                        .getAsInt())
                .filter(x -> x != ranges.stream()
                        .mapToInt(Integer::intValue)
                        .min()
                        .getAsInt())

                .collect(Collectors.toList());
        assertThat(collect).hasSize(13);   // OK
        assertThat(collect).isEqualTo(Lists.newArrayList(new Range(2,14)));   // OK

这段代码很好(只要我们没有重复的最小值/最大值,但这不是这里的核心问题),但问题是我在这里使用了三个流。第一个是主流,第二个是删除最大值,第三个是删除最小值。 是否有可能在一个流中完成这项任务?

//编辑: 非常原始的Scala版本:

val list = List.range(1, 15).sortWith(_>_).tail.reverse.tail

有额外的排序,因为我们可以有随机列表。

java collections java-8 java-stream
3个回答
28
投票

别忘了

Collection.removeIf
。您可以计算最小值和最大值,然后执行以下操作:

list.removeIf(x -> x == min || x == max);

(这也可以很好地处理重复项。)


6
投票

该解决方案不是很有效,但我认为它符合您的要求 - 它可以满足您的要求,并且它位于一个单一的管道中 - 一个批量数据操作序列,Java 8 是如何称呼它的。

import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;

Stream<Integer> ranges = Stream.iterate(1, i -> i + 1).limit(15);
List<Integer> collect = ranges
    .sorted(Comparator.reverseOrder()) // sort the stream from the highest to the smallest
    .skip(1)                           // discards 1 element from the beginning
    .sorted()                          // sort the stream from the smallest to the highest
    .skip(1)                           // discards 1 element from the beginning
    .collect(Collectors.toList())     
    ;

但是,正如 fge 所建议的和 Marco13 在您的问题下面的评论中所写的那样,对流进行排序、终止到列表的管道然后删除第一个和最后一个成员会更好、更高效:P 或者甚至更快不排序 - 遍历所有元素,找到最小值和最大值,记住它们的位置,然后删除它们。


0
投票

这在 Java 中非常容易做到,假设

Stream
已经排序。为了匹配您的 Scala 版本,Java 中的内容本质上是相同的。

IntStream
   .rangeClosed(1,15)
   .sorted()            //Sorts the contents
   .limit(14)           //Keeps all except the last element
   .skip(1)             //Removes the min element
   .boxed()
   .toList()
   ;

这给了你这个。

[2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14]

您可以将

IntStream.rangeClosed(1, 15)
替换为任何
Stream<T extends Comparable<T>>
。只要
T extends Comparable<T>
,那么这个策略就有效。

如果

T
未实现
Comparable<T>
,只需提供您自己的
Comparator<T>

record Foo(int value) {}

Stream
   .of(new Foo(1), new Foo(7), new Foo(3), new Foo(2), new Foo(6), new Foo(4), new Foo(5))
   .sorted(Comparator.comparing(Foo::value))
   .limit(6)
   .skip(1)
   .toList()
   ;

这给了你这个。

[Foo[value=2], Foo[value=3], Foo[value=4], Foo[value=5], Foo[value=6]]
© www.soinside.com 2019 - 2024. All rights reserved.