• Post Reply Bookmark Topic Watch Topic
  • New Topic
programming forums Java Mobile Certification Databases Caching Books Engineering Micro Controllers OS Languages Paradigms IDEs Build Tools Frameworks Application Servers Open Source This Site Careers Other Pie Elite all forums
this forum made possible by our volunteer staff, including ...
Marshals:
  • Campbell Ritchie
  • Tim Cooke
  • paul wheaton
  • Jeanne Boyarsky
  • Ron McLeod
Sheriffs:
  • Paul Clapham
  • Liutauras Vilda
  • Devaka Cooray
Saloon Keepers:
  • Tim Holloway
  • Roland Mueller
Bartenders:

Reduce Stream to Contain Last Element Only

 
Marshal
Posts: 4699
588
VSCode Eclipse IDE TypeScript Redhat MicroProfile Quarkus Java Linux
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
I want to be able to transform a stream with zero or more elements into a stream with zero or one elements, where the element is the last element from the original stream.

The code below does work, but I wondering if there might be a better way where I don't need to process each element one-by-one.

 
Bartender
Posts: 5584
213
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
First thought: intstream iterate from size - 1 to 0, map to the list and limit 1
 
Ron McLeod
Marshal
Posts: 4699
588
VSCode Eclipse IDE TypeScript Redhat MicroProfile Quarkus Java Linux
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Piet Souris wrote:First thought: intstream iterate from size ...


With my case, I don't know the size in-advance, and to discover it, I would need to fully consume the stream.
 
Piet Souris
Bartender
Posts: 5584
213
  • Likes 1
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Can't think of anything useful, so your reduce looks fine, but beware of infinite streams
 
Master Rancher
Posts: 5122
82
  • Likes 1
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
One minor tweak is, there's a shorter way to express the same thing:

While it's a little more concise, it does have the same issue that the original did, in the sense that it looks at the entire stream.  There's not a good built-in solution that I found.  But, I did manage to come up with a solution that seems to work:

The parallel() seems to be necessary, at least in my tests, to get the stream to return a Spliterator that will actually do a split.  Otherwise I kept getting the split() returning null, which means there are no further subdivisions possible.  Interestingly, we're not actually using multiple threads to evaluate the spliterator.  We're just telling the stream to act as if we could use parallel streams, thereby encouraging the split() to allow us to split off some of elements, even if it thinks it could do this faster in a single thread.

To better understand how it works and to experiment with it (and verify that it really can be much faster than reading everything):

Output:

Note that it only evaluates the last element.  For some streams, it might end up having to evaluate more, in cases where it's hard for the Spliterator to estimate size correctly and some splits might not contain any actual elements.
 
Bartender
Posts: 10983
87
Eclipse IDE Firefox Browser MySQL Database VI Editor Java Windows ChatGPT
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
This has been enlightening. Here's both together with some timing.

Output:

 
Piet Souris
Bartender
Posts: 5584
213
  • Likes 1
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Brilliant, Mike, have a cow! Never worked with spliterators, but this is a good starting place.
 
Sheriff
Posts: 22821
132
Eclipse IDE Spring Chrome Java Windows
  • Likes 2
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Be warned that this trySplit is only guaranteed to work if the spliterator is ordered:

https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/util/Spliterator.html#trySplit() wrote:
If this spliterator can be partitioned, returns a Spliterator covering elements, that will, upon return from this method, not be covered by this Spliterator.

If this Spliterator is ORDERED, the returned Spliterator must cover a strict prefix of the elements.


(On the other hand, if the spliterator isn't ordered, then the stream probably wasn't either, and there's no real definition of "last").

It also won't work on infinite streams, but then again, no solution would work on infinite streams as these don't have a last element.

Unless this Spliterator covers an infinite number of elements, repeated calls to trySplit() must eventually return null.

 
Mike Simmons
Master Rancher
Posts: 5122
82
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Yeah, I was thinking about those two issues as well.  I don't know anything to be done about an infinite stream - that's a common problem though.  People creating infinite streams need to get used to ctrl-C. . To be fair, I quite like using infinite streams as building blocks - an infinite stream of primes, for example... with the understanding that you need to make sure there's a way to terminate eventually, when you call a terminal operation.

As for ordering though, we can check that, and throw an informative error:

Unless there's ever a chance that we might want to process a stream not actually marked as ordered, but which nonetheless behaves in an ordered fashion.  Don't know if that's actually possible, perhaps not.  But if someone wanted to try it anyway, they could at least log a warning, rather than throw an exception.
reply
    Bookmark Topic Watch Topic
  • New Topic