集合中出现重复值怎么办?

14

在Set集合中允许重复值是否可行?

是否有办法使元素保持唯一性并拥有一些副本? Set集合是否具有允许重复值的函数?


1
你为什么希望在Set中存储多个值?也许举一个你想要实现的例子会有所帮助。 - Cuga
7
我认为你误解了术语 Set 的整个含义。如果想要重复的元素,请使用列表(List)。 - BalusC
15个回答

28

1
有没有办法使用Set并具有多个值来执行某些操作? - Johanna
5
@Roger,你的Multiset链接指向一个古老版本的源代码。这里有一个最新的javadoc链接:http://guava-libraries.googlecode.com/svn/trunk/javadoc/com/google/common/collect/Multiset.html - Kevin Bourrillion
1
Rojer是正确的。尝试使用java.util.List(首选)或一些第三方库。 除了Google的Collections API之外,您可以使用Apache Commons Collections而无需用户名/密码。请参见下面的答案。 - Gladwin Burboz
1
什么需要用户名和密码?此外,如果只是因为它使用泛型,我肯定会推荐google-collections/guava而不是Apache Commons。 - ColinD

13

一个集合的definition不允许有重复项。也许你需要使用另一种数据结构,比如List,它可以允许重复项。

有没有办法使元素唯一并且拥有一些副本?

如果出于某种原因你真的需要在集合中存储重复项,那么你需要将它们包装在某种持有对象中,或者覆盖模型对象的equals()和hashCode()方法,以使它们不被视为等价的(即使这样做,如果你试图多次存储对同一物理对象的引用,也会失败)。

我认为你需要重新评估你想要实现的目标,或者至少向我们更清楚地解释一下。


2
从javadocs中可以看到:
"集合中不含有一对元素e1和e2,使得e1.equals(e2),并且最多只允许一个null元素"
如果你的对象覆盖了 .equals() 方法,使其对你想要存储的对象返回不同的值,那么就可以将它们分别存储在一个 Set 中(你也应该覆盖 hashCode() 方法)。然而,在Java中,Set 的定义是:
"包含不重复元素的集合"
因此,在这里你最好使用 List 或其他类型的集合。 如果你想基于不同的键存储重复的值,可以考虑使用 Map。

2

关于“bags”(也称为multisets)的Sun公司观点:

我们非常理解对类型安全集合的需求。与其在框架中添加一种以特定方式强制执行类型安全的“绷带”,我们设计了一个可以与当前所有参数化类型提案相适应的框架。如果将参数化类型添加到语言中,整个集合框架将支持编译时类型安全使用,无需显式转换。不幸的是,在1.2版中这不会发生。与此同时,想要运行时类型安全的人们可以在包围JDK集合的“包装器”集合中实现自己的门禁函数。

(来源; 请注意它已经很老并且可能过时 -ed.)

除了Google的集合API之外,您还可以使用Apache Commons Collections。

Apache Commons Collections:

http://commons.apache.org/collections/

Bag的Javadoc


1
那些话(“Sun's view”)是很久以前由Josh Bloch写的。他后来改变了自己的观点,实质上共同设计了Google Collections的Multiset。 - Kevin Bourrillion
Sun在上述声明中的实际意思是,这种情况非常罕见,但如果某些应用程序确实需要这样的功能,则可以通过自定义方式或使用第三方库(例如Apache集合或Google集合)来实现它,而不是将其弄乱核心API。我认为Sun无论如何都没有改变这个观点,因为“袋子”(又名多集)仍然不是最新Java-6的JRE的一部分。 - Gladwin Burboz

1
这些问题听起来像是面试题,因此我会像回答面试题一样回答它们...
Is it possible to allow duplicate values in the Set collection?

是的,但这需要实现Set的人违反构建Set设计合同。基本上,我可以编写一个扩展了Set但不执行Set承诺的类。
此外,其他违规行为也是可能的。我可以使用依赖于Java的hashCode()合同的Set实现。然后,如果我提供了一个违反Java hashcode合同的Object,我可能会将两个相等的对象放入集合中,但由于它们在不同的哈希桶链中,可能不会相互检查相等性而产生不同的哈希码。
Is there any way to make the elements unique and have some copies of them?

这基本上取决于您如何定义“唯一性”。如果一个对象的唯一性是由其值确定的,那么就可以拥有多个相同唯一对象的副本;但是,如果对象的唯一性是由其实例确定的,那么根据定义,不可能拥有多个相同的对象副本。但是,您可以有多个对它们的引用。

Is there any functions for Set collection for having duplicate values in it?

Set接口没有任何用于检测/报告重复项的函数;但是,它基于Collections接口,该接口必须支持List接口,因此可以将重复项传递到Set中;但是,一个正确实现的Set将会忽略重复项,并呈现每个被确定为唯一的元素的一个副本。


1

我不相信在一个集合中可以有重复的值。集合被定义为一组唯一的值。你最好使用ArrayList。


0

您可以通过如下重写hashcode来实现:

public class Test  
{  
    static int a=0;  

    @Override  
    public int hashCode()  
    {  
        a++;  
        return a;  
    }

    public static void main(String[] args)
    {
        Set<Test> s=new HashSet<Test>();
        Test t1=new Test();
        Test t2=t1;
        s.add(t1);
        s.add(t2);
        System.out.println(s);
        System.out.println("--Done--");
    }
}

这违反了哈希码的后置条件,例如每个对象都是持久的...这是一种有点迂腐的说法,即“这是一个完全无法使用的完全破碎的集合”。 - djechlin
这相当丑陋。它违反了hashCode()和equals()的契约。 - Richard Neish

0
你可以使用Tree Map代替:
键可以用作您希望存储的元素,而值将是输入元素的频率。
插入和删除将需要自定义处理。
1.插入:检查映射是否已包含该元素,如果是,则增加其频率。O(log N) 2.删除:如果元素的频率为1,则删除它,否则将频率减少1。O(log N)
更多详细信息可以在Tree Map的java docs中找到。
总体时间复杂度与TreeSet的O(log N)相同,但不如HashSet的O(1)。
firstEntry() -> provides smallest element entry, Time Complexity : O(Log N)
lastEntry() -> provides greatest element entry, Time Complexity : O(Log N)

0

我不这么认为。唯一的方法是使用List。你也可以通过equals()、hashcode()或compareTo()函数来欺骗,但这会很尴尬。


0

没有机会...在SET接口中不能有重复的值... 如果你想要重复值,可以尝试使用Array-List


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接