在几种编程语言中,存在集合集合,它们应该是有限集合的数学概念的实现。
但是,这不一定是真的,例如在C#
和Java
中,HashSet<T>
的两种实现都允许您添加任何HashSet<T>
集合作为其自身的成员。其中一个数学集的现代定义是不允许的。
背景
根据朴素集理论,集合的定义是:
集合是不同对象的集合。
然而,这个定义引人注目的是Russel's Paradox以及其他悖论。为方便起见,罗素的悖论是:
设R是不属于自己的所有集合的集合。如果R 它不是自己的成员,然后它的定义规定它必须 包含它自己,如果它包含它自己,那么它与它自己相矛盾 定义为不属于自己的所有集合的集合。
所以根据现代集理论(参见:ZFC),集合的定义是:
集合是不同对象的集合,其中没有一个是集合 本身。
具体来说,这是axiom of regularity的结果。
那么什么?这有什么影响?为什么StackOverflow上有这个问题?
罗素悖论的一个含义是并非所有集合都是集合。此外,这是数学家将集合的定义作为通常的英语定义。所以我认为这个问题在编程语言设计方面有很大的重要性。
问题(S):
那么为什么编程语言,在某种形式下,在他们的设计中使用这些原则只是在他们的语言库中实现Set时忽略它?
其次,这是否与其他数学概念的实现相同?
也许我有点挑剔,但如果这些是真正的集合实现,那么为什么要忽略这个定义的一部分呢?
更新
添加C#和Java代码段,举例说明行为:
Java代码段
Set<Object> hashSet = new HashSet<Object>();
hashSet.add(1);
hashSet.add("Tiger");
hashSet.add(hashSet);
hashSet.add('f');
Object[] array = hashSet.toArray();
HashSet<Object> hash = (HashSet<Object>)array[3];
System.out.println("HashSet in HashSet:");
for (Object obj : hash)
System.out.println(obj);
System.out.println("\nPrinciple HashSet:");
for (Object obj : hashSet)
System.out.println(obj);
打印出来:
HashSet in HashSet:
f
1
Tiger
[f, 1, Tiger, (this Collection)]
Principle HashSet:
f
1
Tiger
[f, 1, Tiger, (this Collection)]
C#Snippet:
HashSet<object> hashSet = new HashSet<object>();
hashSet.Add(1);
hashSet.Add("Tiger");
hashSet.Add(hashSet);
hashSet.Add('f');
object[] array = hashSet.ToArray();
var hash = (HashSet<object>)array[2];
Console.WriteLine("HashSet in HashSet:");
foreach (object obj in hash)
Console.WriteLine(obj);
Console.WriteLine("\nPrinciple HashSet:");
foreach (object obj in hashSet)
Console.WriteLine(obj);
打印出来:
HashSet in HashSet:
1
Tiger
System.Collections.Generic.HashSet`1[System.Object]
f
Principle HashSet:
1
Tiger
System.Collections.Generic.HashSet`1[System.Object]
f
更新2
关于 Martijn Courteaux 的第二点,即它可以以计算效率的名义完成:
我在C#中创建了两个测试集合。它们是相同的,除了其中一个的Add方法之外 - 我添加了以下检查:if (this != obj)
其中obj
是要添加到集合中的项目。
我将它们分别计时,以便添加100,000个随机整数:
带检查: ~28毫秒
不检查: ~21毫秒
这是一个相当重要的性能跳跃。
答案 0 :(得分:9)
编程语言集实际上不像ZFC集,但原因与你想象的完全不同:
你不能通过理解形成一个集合(即所有对象的集合......)。请注意,这已经阻止了所有(我相信)天真的集理论悖论,因此它们无关紧要。
他们通常不能无限。
存在不是集合的对象(在ZFC中只有 集合)。
它们通常是可变的(即您可以在集合中添加/删除元素)。
它们包含的对象可以是可变的。
答案
那么为什么编程语言,在某种形式下,在他们的设计中使用这些原则只是在他们的语言库中实现Set时忽略它?
是语言不使用这些原则。
答案 1 :(得分:4)
嗯,我认为这是由于某些原因:
对于非常特定的编程目的,您可能希望创建一个包含自身的集合。当你这样做时,你并不是真正关心数学集的意义,而只是想享受Set
提供的功能:“添加”元素而不会产生重复条目。 (我必须说实话,我想不出你想要这样做的情况。)
出于性能目的。您想要使用Set并让它包含自身的机会非常罕见。因此,每次尝试添加元素时,检查计算能力,能量,时间,性能和环境健康都是浪费。
答案 2 :(得分:3)
我不能代表C#,但就Java而言,集合是一个集合。如果你看the javadoc for the Set interface,你会看到(强调我的):
注意:如果将可变对象用作set元素,则必须非常小心。如果在对象是集合中的元素的同时以影响等于比较的方式更改对象的值,则不指定集合的行为。 此禁令的一个特例是,不允许集合将自身包含为元素。
禁止是否被主动强制执行还不清楚(例如,向自身添加HashSet不会引发任何异常),但至少有明确记录表明您不应该尝试,因为行为将会被指定。
答案 3 :(得分:0)
在java中,集合是数学集合。您可以插入对象,但只有一个可以在集合中。来自javadoc的关于set的信息:
“不包含重复元素的集合。更正式地说,集合不包含e1.equals(e2)元素对e1和e2,最多只有一个null元素。正如其名称所暗示的,这个接口模拟了数学集抽象。“