应用条件逻辑获取 Java 列表中最早的 n 个元素

Getting oldest n elements of a Java list with conditional logic applied

Java 8. 我有一个小部件列表 (List<Widget>),其中一个小部件如下所示:

public class Widget {

  // lots of fields
  private Date createTime;

  // getters, setters & ctors
  
}

所有 createTime 值都将是过去; none 以后。而现在并不真正存在。 ;-)

我无法控制小部件列表的创建方式或创建数量。但是小部件列表可能很大,所以我需要使用这个小部件列表来确定要删除哪些小部件 (deleteList)。但是,我需要将一些 Stream API filters/magic 应用于此列表,以便我结束:

  1. 如果小部件的数量 (numWidgets) 小于或等于我要保留的数量 (retentionSize),那么我想保留所有小部件,所以我想要我的deleteList为空
  2. else,numWidgets > retentionSize,所以我希望我的 deleteList 只包含 oldest numWidgets - retentionSize(我将提供一个示例下)

同样这里的算法是:

if numWidgets > retentionSize
  i want oldest (numWidgets - retentionSize)

if numWidgets <= retentionSize
  i want an empty list

示例:

  1. numWidgets是83,retentionSize是90;因为 numWidgets <= retentionSize 那么 deleteList 是空的
  2. numWidgets是107,retentionSize是90;因为 numWidgets > retentionSize 那么 deleteList 是列表中 最旧的 numWidgets - retentionSize (107 - 90 = 17) 个小部件

到目前为止,我使用 Stream API 的最佳尝试是:

// again I don't control how I get allWidgets
List<Widget> allWidgets = getSomehow();
int numWidgets = allWidgets.size();
List<Widget> oldest = (numWidgets > retentionSize)
  ? allWidgets.sort(Comparator.comparing(widget -> widget.getCreateTime()))
  : Collections.emptyList();

这次尝试的几个问题:

谁能帮我冲过终点线?

使用skip(long n)操作:

    List<Integer> allWidgets = List.of(1,2,3,4,5,6);
    int retentionSize = 2;
    List<Integer> result = allWidgets.stream().skip(retentionSize).collect(Collectors.toList());
    System.out.println(result);

或者您可以使用 limit(long maxSize),具体取决于您对列表的排序方式。

首先,您应该对流进行排序,而不是对列表进行排序。第一个元素应该是最新的。

然后是 skip 第一个 retentionSize 个小部件。您跳过的元素多于流中的元素并不重要。 skip 不在乎。现在,只有最旧的 (numWidgets - retentionSize) 小部件保留在流中。

List<Widget> allWidgets = getSomehow();
List<Widget> deleteList = allWidgets.stream()
                          .sorted(Comparator.comparing(Widget::getCreateTime).reversed())
                          .skip(retentionSize)
                          .collect(Collectors.toList());

这每次都会对列表进行排序,即使 retentionSize 大于小部件的数量。如果这导致了性能问题,您可以为此添加一个显式检查:

List<Widget> deleteList;
if (numWidgets > retentionSize) {
    deleteList = allWidgets.stream()
                 .sorted(Comparator.comparing(Widget::getCreateTime).reversed())
                 .skip(retentionSize)
                 .collect(Collectors.toList());
} else {
    deleteList = List.of();
}

如果您想要所有 deleteList 中的元素(就像您已删除它们一样),请使用 limit:

List<Widget> allWidgets = getSomehow();
List<Widget> thingsNotInDeleteList = allWidgets.stream()
                          .sorted(Comparator.comparing(Widget::getCreateTime).reversed())
                          .limit(retentionSize)
                          .collect(Collectors.toList());

Widgets必须根据createTime[=17=按自然顺序排序] 最旧的小部件排在第一位

List<Widget> deleteList = (numWidgets > retentionSize)
    ? allWidgets.stream()
        .sorted((w1, w2) -> w1.getCreateTime().compareTo(w2.getCreateTime()))
        .limit(numWidgets - retentionSize).collect(toList())
        : Collections.emptyList();

试试这个:

List<Widget> deleteList = getSomehow().stream()
                                      .sorted(comparing(Widget::getCreateTime))
                                      .skip(retentionSize)
                                      .collect(toList());

如果您想立即删除所有那些最旧的小部件或执行其他操作,那么您可以使用 forEach 而不是 collect:

getSomehow().stream()
            .sorted(comparing(Widget::getCreateTime))
            .skip(retentionSize)
            .forEach(w -> /* do something here */);