获取LinkedHashSet的最后一个元素

32

我想存储数字列表 1,2,3,4 - (让我们从 List<Integer> 开始)

我希望确保数字是唯一的(好的,使用 Set<Integer>

我希望保证顺序(好的...使用 LinkedHashSet<Integer>

我希望能够获取列表中的最后一个元素...

请问,获取插入到 LinkedHashSet<Integer> 中的最后一个数字的最简单方法是什么?


难以置信的是,Java的LinkedHashSet提供了一个用于第一个元素的迭代器,但没有提供最后一个元素的迭代器...不过,这似乎是事实。参见https://dev59.com/cHI-5IYBdhLWcg3wR2Jr,其中列出了一些第三方库。 - rogerdpack
6个回答

16

针对此问题,没有预制选项。有两个临时解决方案,但都不好:

Order n 方法:

public <E> E getLast(Collection<E> c) {
    E last = null;
    for(E e : c) last = e;
    return last;
}

呸!但也有一种Order 1的方法:

class CachedLinkedHashSet<E> extends LinkedHashSet<E> {
    private E last = null;

    @Override
    public boolean add(E e) {
        last = e;
        return super.add(e);
    }
    public E getLast() {
        return last;
    }

}

这是即兴发挥的,所以可能存在细微的错误,并且肯定不是线程安全的。您的需求可能因此而有所不同,并采取一种方法而不是另一种。


5
缓存方法使得移除操作的时间复杂度为O(n)。 - SLaks
1
@SLaks并不是完全正确的。从技术上讲,这两种方法有着不同的契约。 getLast 方法只是告诉您最后一个添加的元素。它不能保证该元素仍在列表中。 - corsiKa
3
但这可能不是原帖作者想要的。 - SLaks
1
这正是所要求的。“获取最后插入的数字的最简单方法是什么”。无论如何,我仍在寻找更完善的解决方案,因为即使您记录了这一事实,用户仍可能感到惊讶。 - corsiKa
2
如果我要猜的话,可能是因为我没有在<E>中扩展extends LinkedHashSet - 就像我说的那样,可能有一个微妙的错误 - 我只是凭记忆写下来的...显然是在圣诞前夕哈哈...这就解释了为什么我没有编译它! :) - corsiKa
显示剩余4条评论

9
使用,您可以获得一个顺序的Stream,其中包含LinkedHashSet,跳过前n-1个元素并获取最后一个。
Integer lastInteger = set.stream().skip(s.size()-1).findFirst().get();

4
据我所知,这与遍历所有元素没有区别。 - Brett Okken
根据OpenJDK源代码,Spliterator是基于Iterator的默认Spliterator。http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/8-b132/java/util/LinkedHashSet.java?av=f#193 - Brett Okken
@BrettOkken 我对源代码还不是很熟悉,但我猜有趣的部分更多在这里:http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/8-b132/java/util/stream/SliceOps.java#SliceOps.makeRef%28java.util.stream.AbstractPipeline%2Clong%2Clong%29。看起来在之前会初始化一个新的Sink到min(skip, size),所以我不确定它是否会遍历所有元素。 - Alexis C.
2
据我所知,“skip”功能是基于Spliterator的trySplit方法实现的。在LinkedHashSet的情况下,它使用IteratorSpliterator,该迭代器简单地遍历值。http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/8-b132/java/util/Spliterators.java?av=f#1784 - Brett Okken
@BrettOkken 文档说明跳过操作是一种廉价操作。虽然这段代码源码很混乱难以阅读,但你的意思基本上是说跳过不是O(1)操作?尽管问题在于什么是获取最后一个元素的最简单方法,我认为这个方法是最简单的 :-) - Alexis C.
显示剩余2条评论

5

首先,我同意corsiKa的解决方案,该方案建议扩展LinkedHashSet类,包含指向最后一个元素的指针。但是,您也可以使用传统方法通过使用一些数组空间来解决:

set.toArray()[ set.size()-1 ] // returns the last element.

17
我担心这需要一直追溯到 AbstractCollection.toArray() 方法,因为只是为了获取最后一个元素而进行整个集合的硬复制。非常低效。 - Vojtěch
2
这似乎没有任何好处,只是像@corsiKa在下面建议的那样遍历所有条目以获取最后一个。 - Brett Okken

4

自Java 21以来,LinkedHashSet已经具有getLast()方法:

jshell> var set = new LinkedHashSet<>(List.of(1,2,3,4,5));
set ==> [1, 2, 3, 4, 5]

jshell> set.getLast();
$2 ==> 5

-1
这是一个实现,它添加了访问最后一个条目 O(1) 的方法:

LinkedHashSetEx.java

享受...


3
请不要依赖第三方链接来回答问题。这个链接随时可能停止工作,那么你的答案就会变得无用。 - Simon Forsberg
请注意,此示例使用反射访问java.util.LinkedHashMap的私有成员,这可能会导致安全异常。 - corsiKa

-5

集合与顺序无关。我们不能通过索引访问元素。如果您需要最后一个元素,

1)创建新的ArrayList(Set)

可以轻松访问ArrayList的最后一个元素。


6
问题明确提到了LinkedHashSet,它具有固有顺序(在javadoc中定义为添加到集合中的唯一项的顺序)。 - Simon B

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接