Generalize PySequence_Count() (operator.countOf) to work with iterators.

This commit is contained in:
Tim Peters 2001-05-05 11:33:43 +00:00
parent 1434299a99
commit 75f8e35ef4
3 changed files with 70 additions and 15 deletions

View File

@ -527,4 +527,39 @@ class TestCase(unittest.TestCase):
except OSError:
pass
# Test iterators with operator.countOf (PySequence_Count).
def test_countOf(self):
from operator import countOf
self.assertEqual(countOf([1,2,2,3,2,5], 2), 3)
self.assertEqual(countOf((1,2,2,3,2,5), 2), 3)
self.assertEqual(countOf("122325", "2"), 3)
self.assertEqual(countOf("122325", "6"), 0)
self.assertRaises(TypeError, countOf, 42, 1)
self.assertRaises(TypeError, countOf, countOf, countOf)
d = {"one": 3, "two": 3, "three": 3, 1j: 2j}
for k in d:
self.assertEqual(countOf(d, k), 1)
self.assertEqual(countOf(d.itervalues(), 3), 3)
self.assertEqual(countOf(d.itervalues(), 2j), 1)
self.assertEqual(countOf(d.itervalues(), 1j), 0)
f = open(TESTFN, "w")
try:
f.write("a\n" "b\n" "c\n" "b\n")
finally:
f.close()
f = open(TESTFN, "r")
try:
for letter, count in ("a", 1), ("b", 2), ("c", 1), ("d", 0):
f.seek(0, 0)
self.assertEqual(countOf(f, letter + "\n"), count)
finally:
f.close()
try:
unlink(TESTFN)
except OSError:
pass
run_unittest(TestCase)

View File

@ -23,10 +23,12 @@ Core
max()
min()
reduce()
tuple() (PySequence_Tuple() and PySequence_Fast() in C API)
.join() method of strings
tuple()
'x in y' and 'x not in y' (PySequence_Contains() in C API)
operator.countOf() (PySequence_Count() in C API)
XXX TODO zip()
'x in y' and 'x not in y'
What's New in Python 2.1 (final)?
=================================

View File

@ -1333,34 +1333,52 @@ PySequence_Fast(PyObject *v, const char *m)
return v;
}
/* Return # of times o appears in s. */
int
PySequence_Count(PyObject *s, PyObject *o)
{
int l, i, n, cmp, err;
PyObject *item;
int n; /* running count of o hits */
PyObject *it; /* iter(s) */
if (s == NULL || o == NULL) {
null_error();
return -1;
}
l = PySequence_Size(s);
if (l < 0)
it = PyObject_GetIter(s);
if (it == NULL) {
type_error(".count() requires iterable argument");
return -1;
}
n = 0;
for (i = 0; i < l; i++) {
item = PySequence_GetItem(s, i);
if (item == NULL)
return -1;
err = PyObject_Cmp(item, o, &cmp);
for (;;) {
int cmp;
PyObject *item = PyIter_Next(it);
if (item == NULL) {
if (PyErr_Occurred())
goto Fail;
break;
}
cmp = PyObject_RichCompareBool(o, item, Py_EQ);
Py_DECREF(item);
if (err < 0)
return err;
if (cmp == 0)
if (cmp < 0)
goto Fail;
if (cmp > 0) {
if (n == INT_MAX) {
PyErr_SetString(PyExc_OverflowError,
"count exceeds C int size");
goto Fail;
}
n++;
}
}
Py_DECREF(it);
return n;
Fail:
Py_DECREF(it);
return -1;
}
/* Return -1 if error; 1 if v in w; 0 if v not in w. */