64

I have a collection, I want to get the last element of the collection. What's the most straighforward and fast way to do so?

One solution is to first toArray(), and then return the last element of the array. Is there any other better ones?

tom
  • 14,273
  • 19
  • 65
  • 124

9 Answers9

66

A Collection is not a necessarily ordered set of elements so there may not be a concept of the "last" element. If you want something that's ordered, you can use a SortedSet/NavigableSet which has a last() method. Or you can use a List and call mylist.get(mylist.size()-1);

If you really need the last element you should use a List or a SortedSet/NavigableSet. But if all you have is a Collection and you really, really, really need the last element, you could use toArray() or you could use an Iterator and iterate to the end of the list.

For example:

public Object getLastElement(final Collection c) {
    final Iterator itr = c.iterator();
    Object lastElement = itr.next();
    while(itr.hasNext()) {
        lastElement = itr.next();
    }
    return lastElement;
}
Basil Bourque
  • 303,325
  • 100
  • 852
  • 1,154
Jack Edmonds
  • 31,931
  • 18
  • 65
  • 77
  • I only have collection available, I don't know it's fundamental type be it array, list or others. So, to use SortedSet, I would have to firstly construct the SortedSet using the collection, and then do the rest of work. Will that be expensive? – tom Dec 02 '11 at 18:28
  • @tom It would probably be O(n*lg(n)) to construct the `SortedSet` (if you constructed it all at once). So depending on how many items you expect to have, it could be rather expensive. Usually, if your underlying type is ordered, you can at least cast it to a `List` even if you don't know what type of `List` it is. – Jack Edmonds Dec 02 '11 at 18:32
  • Thanks @Jack, assume my data is sorted when returning to me, as they are the case, will there be another solution? – tom Dec 02 '11 at 18:35
  • @tom If you're guaranteed to get sorted data, you can *probably* assume the Collection's type implements `SortedSet` or at least `List`. However, if you still can make no assumptions about the underlying type, then you're stuck with the API exposed by `Collection` which won't make it easy to find the last element as a `Collection` doesn't have a concept of a last element. Thus, you'll need to iterate through and find the last element yourself (`toArray` works fine as well assuming you don't have any concerns about memory usage). – Jack Edmonds Dec 02 '11 at 18:39
  • 1
    This throws a NullPointerException when an empty collection is given. Use `Object lastElement = null;` instead to return null in case of an empty collection. – Markus Pscheidt Oct 01 '15 at 15:19
  • can also make the method static too – riddle_me_this Apr 01 '16 at 20:01
  • Any reason to use the iterator instead of converting to array and getting the last index? – Sina Madani Apr 04 '18 at 10:29
  • @SinaMadani it takes less additional space to use the iterator. – Jack Edmonds Apr 17 '18 at 19:49
  • "last" have nothing to do with sorting as your said List(array) can have its last element. It just is java design defect – jean Oct 17 '18 at 06:41
  • This one has the drawback of the reallocation of the `lastElement` variable every iteration of the while loop, but works as spected. – Alex Vergara Jul 08 '22 at 12:13
61

Iterables.getLast from Google Guava. It has some optimization for Lists and SortedSets too.

palacsint
  • 28,416
  • 10
  • 82
  • 109
15

This should work without converting to List/Array:

collectionName.stream().reduce((prev, next) -> next).orElse(null)
Samad Charania
  • 151
  • 1
  • 2
14

It is not very efficient solution, but working one:

public static <T> T getFirstElement(final Iterable<T> elements) {
    return elements.iterator().next();
}

public static <T> T getLastElement(final Iterable<T> elements) {
    T lastElement = null;

    for (T element : elements) {
        lastElement = element;
    }

    return lastElement;
}
Community
  • 1
  • 1
nikolai.serdiuk
  • 762
  • 8
  • 11
  • It actually is quite efficient. In fact, as efficient as it can be without to trying to cast the iterable to any more specific type (well, `List`). – Dmitry Ginzburg Feb 22 '21 at 20:57
10

Well one solution could be:

list.get(list.size()-1)

Edit: You have to convert the collection to a list before maybe like this: new ArrayList(coll)

kukudas
  • 4,834
  • 5
  • 44
  • 65
  • So I need to construct the list using the collection first. Performance wise, will that be different from toArray solution? – tom Dec 02 '11 at 18:30
  • If all you are doing is getting the last element it is more efficient to use toArray() than build an ArrayList – mwk Oct 06 '13 at 04:41
  • 1
    Question mentions it is a collection not a list. Now, for converting it to a list just to have the last element is a bad solution and can lead to performance bottlenecks if you have large collections. Use Guava's Iterable.getLast method instead. – javadev Feb 16 '17 at 09:16
  • If you have to bring yourself to convert it (which will copy it), you might as well just use one of the iterative solutions... – Bill K Apr 04 '19 at 22:13
6

A reasonable solution would be to use an iterator if you don't know anything about the underlying Collection, but do know that there is a "last" element. This isn't always the case, not all Collections are ordered.

Object lastElement = null;

for (Iterator collectionItr = c.iterator(); collectionItr.hasNext(); ) {
  lastElement = collectionItr.next();
}
Nick Garvey
  • 2,980
  • 24
  • 31
  • 1
    Correct, I don't know the underlying type of the collection. But if it's a big collection, then it'll be a O(N) solution. I am essentially looking for a O(1) solution. – tom Dec 02 '11 at 18:31
  • 1
    That isn't possible. Consider trying to get the last element of a singly linked list. That operation *has* to be O(n), there is no generic O(1) answer. – Nick Garvey Dec 02 '11 at 18:54
0

Or you can use a for-each loop:

Collection<X> items = ...;
X last = null;
for (X x : items) last = x;
assylias
  • 321,522
  • 82
  • 660
  • 783
0

If you have Iterable convert to stream and find last element

 Iterator<String> sourceIterator = Arrays.asList("one", "two", "three").iterator();

 Iterable<String> iterable = () -> sourceIterator;


 String last = StreamSupport.stream(iterable.spliterator(), false).reduce((first, second) -> second).orElse(null);
ravthiru
  • 8,878
  • 2
  • 43
  • 52
0

There isn't a last() or first() method in a Collection interface. For getting the last method, you can either do get(size() - 1) on a List or reverse the List and do get(0). I don't see a need to have last() method in any Collection API unless you are dealing with Stacks or Queues

Piyush Mattoo
  • 15,454
  • 6
  • 47
  • 56