google / guava

Google core libraries for Java
Apache License 2.0
49.99k stars 10.85k forks source link

Provide an Iterables.tail() method #1906

Open dimo414 opened 9 years ago

dimo414 commented 9 years ago

I have a need to select the most recent n elements from a list that I know is ordered; for instance, to display data from the last ten years, in a (potentially long) list of data ordered by year.

For existing Lists it's tedious but not complicated to write out:

list.subList(Math.max(list.size() - n, 0), list.size())

though I'd argue the cleanliness of a simple .tail() method is still a nice win over the above. More valuable however is providing support for arbitrary Iterables, in order to avoid creating a copy of the whole data stream simply to take a small sublist. I imagine many users (myself included) simply absorb the cost of the full copy rather than take the time to implement a circular buffer or similar memory-efficient solution.

lowasser commented 9 years ago

AFAIK, most languages' concept associated with the word "tail" would not be the last n elements, but rather, equivalent to skipping the first n elements. We might need a different name here.

On Mon Dec 08 2014 at 5:38:56 PM Michael Diamond notifications@github.com wrote:

I have a need to select the most recent n elements from a list that I know is ordered; for instance, to display data from the last ten years, in a (potentially long) list of data ordered by year.

For existing Lists it's tedious but not complicated to write out:

list.subList(Math.max(list.size() - n, 0), list.size())

though I'd argue the cleanliness of a simple .tail() method is still a nice win over the above. More valuable however is providing support for arbitrary Iterables, in order to avoid creating a copy of the whole data stream simply to take a small sublist. I imagine many users (myself included) simply absorb the cost of the full copy rather than take the time to implement a circular buffer or similar memory-efficient solution.

— Reply to this email directly or view it on GitHub https://github.com/google/guava/issues/1906.

cgdecker commented 9 years ago

@lowasser: Hmm, any examples? We use skip for that, as does Java 8's Stream. tail is also a Unix command that outputs the last n lines of something.

lowasser commented 9 years ago

Hmmm. I was thinking about Haskell, where "tail" refers to a list without its first element, and doesn't really have a name for that feature that I can think of?

I do think that e.g. FluentIterable.last(5) would be fairly unambiguous, though, FWIW.

On Mon Dec 08 2014 at 5:52:40 PM Colin Decker notifications@github.com wrote:

@lowasser https://github.com/lowasser: Hmm, any examples? We use skip for that, as does Java 8's Stream. tail is also a Unix command that outputs the last n lines of something.

— Reply to this email directly or view it on GitHub https://github.com/google/guava/issues/1906#issuecomment-66203552.

cgdecker commented 9 years ago

Few thoughts:

vorburger commented 9 years ago

I understand that this issue is about a new method for getting the tailing/last/trailing N elements, but if anyone hits this page while searching for a method to find THE last element, as I just have, then FYI com.google.common.collect.Iterables's T getLast(Iterable iterable) is what you are looking for (it's optimized for List).

kevinb9n commented 9 years ago

Note that our current offering here is EvictingQueue.

Queue<Foo> q = EvictingQueue.create(n);
q.addAll(everything);
for (Foo foo : q) { ... }
dimo414 commented 7 years ago

Just to mention that a302923027 makes EvictingQueue a little more efficient for this use-case, but it's still not as discoverable or intuitive as a method on Iterables would be.