java LinkedHashSet - 插入顺序和重复项 - 保持最新的“在顶部”

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/36399845/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-11-03 01:24:12  来源:igfitidea点击:

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

javalistlinkedhashset

提问by rafakob

I need a collection that keeps insertion order and has unique values. LinkedHashSet looks like the way to go, but there's one problem - when two items are equal, it removes the newest one (which makes sense), here's an example:

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

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

The LinkedHashSetwill print:

LinkedHashSet会打印:

one, two, three

one, two,three

But what I need is:

但我需要的是:

one, three, two

one, three,two

What would be the best solution here? Is there any collection/collections method that can do this or should I implement it manually?

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

回答by OldCurmudgeon

Most of the Java Collectionscan be extended for tweaking.

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

Subclass LinkedHashSet, overriding the addmethod.

子类LinkedHashSet,覆盖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;
    }

}

回答by Holger

You can simply use a special feature of LinkedHashMap:

您可以简单地使用以下特性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]

In Oracle's JRE the LinkedHashSetis backed by a LinkedHashMapanyway, so there's not much functional difference, but the special constructor used here configures the LinkedHashMapto change the order on every accessnot only on insertion. This might sound as being too much, but in fact affects the insertion of already contained keys (values in the sense of the Set) only. The other affected Mapoperations (namely get) are not used by the returned Set.

在 Oracle 的 JRE 中,无论如何LinkedHashSet都由 a 支持LinkedHashMap,所以没有太大的功能差异,但是这里使用的特殊构造函数配置了LinkedHashMap以更改每次访问的顺序,而不仅仅是插入。这听起来可能太多了,但实际上仅影响已包含的键( 意义上的值)的插入Set。其他受影响的Map操作(即get)不被返回的Set.

If you're not using Java?8, you have to help the compiler a bit due to the limited type inference:

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

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

but the functionality is the same.

但功能是一样的。

回答by Toonijn

When initializing you're LinkedHashSet you could override the add method.

初始化时,您是 LinkedHashSet,您可以覆盖 add 方法。

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

Now it gives you:

现在它给你:

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

// [3, 1 ,2]

even the addAll method is working.

甚至 addAll 方法也在起作用。

回答by Naresh Joshi

All solution provided above are excellent but if we don't want to override already implemented collections. We can solve this problem simply by using an ArrayList with a little trick

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

We can create a method which you will use to insert data into your list

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

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 
}

And we can call this method to add element to our list

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

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

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

Only disadvantage here is we need to call our custom addToList()method everytime instead of list.add()

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