LinkedHashSet - 插入顺序和重复 - 保持最新"在顶部"

时间:2016-04-04 10:10:52

标签: java list linkedhashset

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

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

LinkedHashSet将打印:

  

onetwothree

但我需要的是:

  

onethreetwo

这里最好的解决方案是什么?是否有任何可以执行此操作的集合/集合方法,还是应该手动实现它?

4 个答案:

答案 0 :(得分:34)

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

子类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;
    }

}

答案 1 :(得分:18)

您只需使用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来改变每个<的顺序em> access 不仅适用于插入。这可能听起来太多了,但实际上只会影响已包含的键(Set意义上的值)的插入。其他受影响的Map操作(即get)未被返回的Set使用。

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

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

但功能相同。

答案 2 :(得分:6)

初始化您的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方法也在工作。

答案 3 :(得分:1)

如果我们不想覆盖已经实现的集合,那么上面提供的所有解决方案都非常出色。我们可以通过使用带有小技巧的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()