我对使用 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
有额外的排序,因为我们可以有随机列表。
别忘了
Collection.removeIf
。您可以计算最小值和最大值,然后执行以下操作:
list.removeIf(x -> x == min || x == max);
(这也可以很好地处理重复项。)
该解决方案不是很有效,但我认为它符合您的要求 - 它可以满足您的要求,并且它位于一个单一的管道中 - 一个批量数据操作序列,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 或者甚至更快不排序 - 遍历所有元素,找到最小值和最大值,记住它们的位置,然后删除它们。
这在 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]]