LinkedHashSet - 插入顺序和重复 - 保持最新 "on top"

LinkedHashSet - insertion order and duplicates - keep newest "on top"

我需要一个保持插入顺序并具有唯一值的集合。 LinkedHashSet 看起来像是要走的路,但有一个问题 - 当两个项目相等时,它会删除最新的一个(这是有道理的),这是一个例子:

set.add("one");
set.add("two");
set.add("three");
set.add("two");

LinkedHashSet 将打印:

one, two, three

但我需要的是:

one, three, two

最好的解决方案是什么?是否有任何 collection/collections 方法可以做到这一点,或者我应该手动实施它?

初始化 LinkedHashSet 时,您可以重写 add 方法。

Set<String> set = new LinkedHashSet<String>(){
    @Override
    public boolean add(String s) {
        if(contains(s))
            remove(s);
        return super.add(s);
    }
};

现在它给你:

set.add("1");
set.add("2");
set.add("3");
set.add("1");
set.addAll(Collections.singleton("2"));

// [3, 1 ,2]

连 addAll 方法都在工作。

大多数 Java Collections 都可以扩展以进行调整。

子类 LinkedHashSet, overriding the add 方法。

class TweakedHashSet<T> extends LinkedHashSet<T> {

    @Override
    public boolean add(T e) {
        // Get rid of old one.
        boolean wasThere = remove(e);
        // Add it.
        super.add(e);
        // Contract is "true if this set did not already contain the specified element"
        return !wasThere;
    }

}

你可以简单地使用LinkedHashMap的一个特殊功能:

Set<String> set = Collections.newSetFromMap(new LinkedHashMap<>(16, 0.75f, true));
set.add("one");
set.add("two");
set.add("three");
set.add("two");
System.out.println(set); // prints [one, three, two]

在 Oracle 的 JRE 中,LinkedHashSet 无论如何都由 LinkedHashMap 支持,因此在功能上没有太大区别,但是这里使用的特殊构造函数配置 LinkedHashMap 以更改顺序每个 access 不仅在 insertion 上。这听起来可能太多了,但实际上只会影响已经包含的键(Set 意义上的值)的插入。返回的 Set.

未使用其他受影响的 Map 操作(即 get

如果您不使用 Java 8,由于类型推断有限,您必须稍微帮助编译器:

Set<String> set
    = Collections.newSetFromMap(new LinkedHashMap<String, Boolean>(16, 0.75f, true));

但功能是一样的。

上面提供的所有解决方案都非常好,但如果我们不想覆盖已经实现的集合。我们可以简单地通过一个小技巧使用 ArrayList 来解决这个问题

我们可以创建一个方法,您将使用该方法将数据插入列表

public static <T> void addToList(List<T> list, T element) {
    list.remove(element); // Will remove element from list, if list contains it
    list.add(element); // Will add element again to the list 
}

我们可以调用这个方法来添加元素到我们的列表

List<String> list = new ArrayList<>();

addToList(list, "one");
addToList(list, "two");
addToList(list, "three");
addToList(list, "two");

这里唯一的缺点是我们每次都需要调用我们的自定义方法 addToList() 而不是 list.add()