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

raf*_*kob 33 java list linkedhashset

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

set.add("one");
set.add("two");
set.add("three");
set.add("two");
Run Code Online (Sandbox Code Playgroud)

LinkedHashSet会打印:

one,two,three

但我需要的是:

one,three,two

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

Old*_*eon 34

大多数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;
    }

}
Run Code Online (Sandbox Code Playgroud)

  • @rafakob删除应该在`LinkedHashSet`中更有效,但是你必须确定配置文件(取决于你的`T`s的典型`hashCode`实现的质量和你的集合的典型大小)其他事情) (6认同)
  • @OldCurmudgeon:如果你在插入之前移除了 (2认同)
  • @corsiKa:差异不是像3或4这样的因素,而是*scale*,所以如果给出足够大的集合,就会产生伤害的性能差异.但是,当然,与迭代相比,我们对OP的最大集合大小以及查找/修改的发生频率一无所知...... (2认同)
  • @corsiKa:原则上,我们同意这一点.对于特定的应用程序,分析是关键问题的分析*和*分析,是否可以在不同的场景/生产环境/不同的客户/等处出现明显更多的元素.如果您知道存在内在限制在您的任务中,测试和配置文件与您的预期最大值... (2认同)

Hol*_*ger 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]
Run Code Online (Sandbox Code Playgroud)

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

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

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

但功能是一样的.

  • @Hulk:当然,这对于生产代码来说是正确的.然后,您可能会提供过载以提供容量和负载系数参数.我在这里使用了与默认构造函数相同的值,但是如果没有文档化的工厂方法,它们对于读者来说就像魔术文字一样...... (2认同)

Too*_*ijn 6

初始化您的LinkedHashSet时,您可以覆盖add方法.

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

现在它给你:

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

// [3, 1 ,2]
Run Code Online (Sandbox Code Playgroud)

甚至addAll方法也正常工作.