How to remove the last element from a Stream Collection (DockerClient)

588 Views Asked by At

Hi I have a stream Collection and I sorted it by the date creation, I need to remove all the elements from this Collections, but less the final one:

This is my code:

List<com.spotify.docker.client.messages.Image> response = dockerClient.listImages()
          .stream()
          .filter(image -> image.labels() != null && image.labels().containsKey("wantedLabel"))
          .sorted((o1, o2) -> o2.created().compareTo(o1.created()))
          .collect(
              Collectors.toList());

In this list I have my elements sorted by created date and I need to remove all the elements less the final one.

i tried something like:

 if (response.stream().iterator().hasNext()) {
        response.remove(count);
        count++;
 }

But I wanted to have something more sophisticated, thanks!

2

There are 2 best solutions below

2
On

It seems that an image with the latest created date needs to be retrieved, therefore Collectors::maxBy could be used instead of sorting the list and removing unneeded elements:

Image latestImage = dockerClient.listImages()
          .stream()
          .filter(image -> image.labels() != null && image.labels().containsKey("wantedLabel"))
          .collect(Collectors.maxBy(Image::created)) // Optional<Image>
          .orElse(null);

If it is really needed to have a List as result:

List<Image> response = dockerClient.listImages()
          .stream()
          .filter(image -> image.labels() != null && image.labels().containsKey("wantedLabel"))
          .collect(Collectors.maxBy(Image::created)) // Optional<Image>
          .map(Collections::singletonList)
          .orElseGet(() -> Collections.emptyList());

Update

As soon as the latest image is found, it is possible to use forEach to delete the images from the Docker container if necessary:

List<Image> images = dockerClient.listImages()
    .stream()
    .filter(image -> image.labels() != null && image.labels().containsKey("wantedLabel"))
    .collect(Collectors.toList());

images.stream()
    .collect(Collectors.maxBy(Image::created)) // Optional<Image>
    .ifPresent(latest -> 
        images.stream()
              .filter(img -> !latest.getId().equals(img.getId()))
              .forEach(img -> dockerClient.removeImage(img.getId()))
    );
1
On

This task can be solved simple and efficient with a traditional loop:

com.spotify.docker.client.messages.Image mostRecent = null;
for(var image: dockerClient.listImages()) {
    if(image.labels() == null || !image.labels().containsKey("wantedLabel")) continue;
    if(mostRecent == null) mostRecent = image;
    else {
        var toRemove = image;
        if(toRemove.created().compareTo(mostRecent.created()) > 0) {
            toRemove = mostRecent;
            mostRecent = image;
        }
        dockerClient.removeImage(toRemove.id());
    }
}

This loop iterates over the images and removes an image as soon as a more recent matching object has been found, without the need for additional storage nor sorting. When the loop completes, all but the most recent matching image have been removed and, as a bonus, the retained most recent object is held in the variable mostRecent.