34

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

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

LinkedHashSet打印:

one, two,three

但我需要的是:

one, three,two

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

4

4 回答 4

35

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

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

}
于 2016-04-04T10:35:11.337 回答
20

您可以简单地使用以下特殊功能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都支持 a LinkedHashMap,因此没有太大的功能差异,但这里使用的特殊构造函数将 配置为在每次访问LinkedHashMap时更改顺序,而不仅仅是在插入时。这听起来可能太多了,但实际上只会影响已包含的键(在 的意义上的值)的插入。返回的 不使用其他受影响的操作(即) 。SetMapgetSet

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

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

但功能是一样的。

于 2016-04-04T16:04:52.643 回答
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 方法也有效。

于 2016-04-04T10:32:44.887 回答
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()

于 2016-11-20T06:33:13.730 回答