summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRaymond Hettinger <python@rcn.com>2007-11-08 02:52:43 (GMT)
committerRaymond Hettinger <python@rcn.com>2007-11-08 02:52:43 (GMT)
commit1760c8a017ca87dc3b21d383542a23bca4370b34 (patch)
tree8bd8d6076cba0e0135ef83f46467353fcd3a50f2
parent004c1c15621eff6bda20c66ce4e5d5c49c90ff25 (diff)
downloadcpython-1760c8a017ca87dc3b21d383542a23bca4370b34.zip
cpython-1760c8a017ca87dc3b21d383542a23bca4370b34.tar.gz
cpython-1760c8a017ca87dc3b21d383542a23bca4370b34.tar.bz2
Add set.isdisjoint()
-rw-r--r--Doc/library/stdtypes.rst7
-rw-r--r--Lib/test/test_set.py49
-rw-r--r--Misc/NEWS2
-rw-r--r--Objects/setobject.c70
4 files changed, 126 insertions, 2 deletions
diff --git a/Doc/library/stdtypes.rst b/Doc/library/stdtypes.rst
index a74758b..f394b23 100644
--- a/Doc/library/stdtypes.rst
+++ b/Doc/library/stdtypes.rst
@@ -1467,6 +1467,13 @@ operations:
Test *x* for non-membership in *s*.
+.. method:: set.isdisjoint(other)
+
+ Return True if the set has no elements in common with *other*.
+ Sets are disjoint if and only if their interesection is the empty set.
+
+ .. versionadded:: 2.6
+
.. method:: set.issubset(other)
set <= other
diff --git a/Lib/test/test_set.py b/Lib/test/test_set.py
index 872a467..aba046a 100644
--- a/Lib/test/test_set.py
+++ b/Lib/test/test_set.py
@@ -102,6 +102,20 @@ class TestJointOps(unittest.TestCase):
self.assertEqual(self.thetype('abcba').intersection(C('ccb')), set('bc'))
self.assertEqual(self.thetype('abcba').intersection(C('ef')), set(''))
+ def test_isdisjoint(self):
+ def f(s1, s2):
+ 'Pure python equivalent of isdisjoint()'
+ return not set(s1).intersection(s2)
+ for larg in '', 'a', 'ab', 'abc', 'ababac', 'cdc', 'cc', 'efgfe', 'ccb', 'ef':
+ s1 = self.thetype(larg)
+ for rarg in '', 'a', 'ab', 'abc', 'ababac', 'cdc', 'cc', 'efgfe', 'ccb', 'ef':
+ for C in set, frozenset, dict.fromkeys, str, unicode, list, tuple:
+ s2 = C(rarg)
+ actual = s1.isdisjoint(s2)
+ expected = f(s1, s2)
+ self.assertEqual(actual, expected)
+ self.assert_(actual is True or actual is False)
+
def test_and(self):
i = self.s.intersection(self.otherword)
self.assertEqual(self.s & set(self.otherword), i)
@@ -657,6 +671,18 @@ class TestBasicOps(unittest.TestCase):
result = empty_set & self.set
self.assertEqual(result, empty_set)
+ def test_self_isdisjoint(self):
+ result = self.set.isdisjoint(self.set)
+ self.assertEqual(result, not self.set)
+
+ def test_empty_isdisjoint(self):
+ result = self.set.isdisjoint(empty_set)
+ self.assertEqual(result, True)
+
+ def test_isdisjoint_empty(self):
+ result = empty_set.isdisjoint(self.set)
+ self.assertEqual(result, True)
+
def test_self_symmetric_difference(self):
result = self.set ^ self.set
self.assertEqual(result, empty_set)
@@ -835,6 +861,22 @@ class TestBinaryOps(unittest.TestCase):
result = self.set & set([8])
self.assertEqual(result, empty_set)
+ def test_isdisjoint_subset(self):
+ result = self.set.isdisjoint(set((2, 4)))
+ self.assertEqual(result, False)
+
+ def test_isdisjoint_superset(self):
+ result = self.set.isdisjoint(set([2, 4, 6, 8]))
+ self.assertEqual(result, False)
+
+ def test_isdisjoint_overlap(self):
+ result = self.set.isdisjoint(set([3, 4, 5]))
+ self.assertEqual(result, False)
+
+ def test_isdisjoint_non_overlap(self):
+ result = self.set.isdisjoint(set([8]))
+ self.assertEqual(result, True)
+
def test_sym_difference_subset(self):
result = self.set ^ set((2, 4))
self.assertEqual(result, set([6]))
@@ -1456,11 +1498,14 @@ class TestVariousIteratorArgs(unittest.TestCase):
def test_inline_methods(self):
s = set('november')
for data in ("123", "", range(1000), ('do', 1.2), xrange(2000,2200,5), 'december'):
- for meth in (s.union, s.intersection, s.difference, s.symmetric_difference):
+ for meth in (s.union, s.intersection, s.difference, s.symmetric_difference, s.isdisjoint):
for g in (G, I, Ig, L, R):
expected = meth(data)
actual = meth(G(data))
- self.assertEqual(sorted(actual), sorted(expected))
+ if isinstance(expected, bool):
+ self.assertEqual(actual, expected)
+ else:
+ self.assertEqual(sorted(actual), sorted(expected))
self.assertRaises(TypeError, meth, X(s))
self.assertRaises(TypeError, meth, N(s))
self.assertRaises(ZeroDivisionError, meth, E(s))
diff --git a/Misc/NEWS b/Misc/NEWS
index ff42c1b..17b7833 100644
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -12,6 +12,8 @@ What's New in Python 2.6 alpha 1?
Core and builtins
-----------------
+- sets and frozensets now have an isdisjoint() method.
+
- optimize the performance of builtin.sum().
- Fix warnings found by the new version of the Coverity checker.
diff --git a/Objects/setobject.c b/Objects/setobject.c
index 025a79b..140d945 100644
--- a/Objects/setobject.c
+++ b/Objects/setobject.c
@@ -1332,6 +1332,72 @@ set_iand(PySetObject *so, PyObject *other)
return (PyObject *)so;
}
+static PyObject *
+set_isdisjoint(PySetObject *so, PyObject *other)
+{
+ PyObject *key, *it, *tmp;
+
+ if ((PyObject *)so == other) {
+ if (PySet_GET_SIZE(so) == 0)
+ Py_RETURN_TRUE;
+ else
+ Py_RETURN_FALSE;
+ }
+
+ if (PyAnySet_CheckExact(other)) {
+ Py_ssize_t pos = 0;
+ setentry *entry;
+
+ if (PySet_GET_SIZE(other) > PySet_GET_SIZE(so)) {
+ tmp = (PyObject *)so;
+ so = (PySetObject *)other;
+ other = tmp;
+ }
+ while (set_next((PySetObject *)other, &pos, &entry)) {
+ int rv = set_contains_entry(so, entry);
+ if (rv == -1)
+ return NULL;
+ if (rv)
+ Py_RETURN_FALSE;
+ }
+ Py_RETURN_TRUE;
+ }
+
+ it = PyObject_GetIter(other);
+ if (it == NULL)
+ return NULL;
+
+ while ((key = PyIter_Next(it)) != NULL) {
+ int rv;
+ setentry entry;
+ long hash = PyObject_Hash(key);
+
+ Py_DECREF(key);
+ if (hash == -1) {
+ Py_DECREF(it);
+ return NULL;
+ }
+ entry.hash = hash;
+ entry.key = key;
+ rv = set_contains_entry(so, &entry);
+ if (rv == -1) {
+ Py_DECREF(it);
+ return NULL;
+ }
+ if (rv) {
+ Py_DECREF(it);
+ Py_RETURN_FALSE;
+ }
+ }
+ Py_DECREF(it);
+ if (PyErr_Occurred())
+ return NULL;
+ Py_RETURN_TRUE;
+}
+
+PyDoc_STRVAR(isdisjoint_doc,
+"Return True if two sets have a null intersection.");
+
static int
set_difference_update_internal(PySetObject *so, PyObject *other)
{
@@ -1861,6 +1927,8 @@ static PyMethodDef set_methods[] = {
intersection_doc},
{"intersection_update",(PyCFunction)set_intersection_update, METH_O,
intersection_update_doc},
+ {"isdisjoint", (PyCFunction)set_isdisjoint, METH_O,
+ isdisjoint_doc},
{"issubset", (PyCFunction)set_issubset, METH_O,
issubset_doc},
{"issuperset", (PyCFunction)set_issuperset, METH_O,
@@ -1984,6 +2052,8 @@ static PyMethodDef frozenset_methods[] = {
difference_doc},
{"intersection",(PyCFunction)set_intersection, METH_O,
intersection_doc},
+ {"isdisjoint", (PyCFunction)set_isdisjoint, METH_O,
+ isdisjoint_doc},
{"issubset", (PyCFunction)set_issubset, METH_O,
issubset_doc},
{"issuperset", (PyCFunction)set_issuperset, METH_O,