Add count() method to collections.deque().

This commit is contained in:
Raymond Hettinger 2010-04-03 23:20:46 +00:00
parent 4893abc77a
commit 44459debc6
4 changed files with 73 additions and 1 deletions

View file

@ -338,6 +338,12 @@ counts, but the output will exclude results with counts of zero or less.
Remove all elements from the deque leaving it with length 0. Remove all elements from the deque leaving it with length 0.
.. method:: count(x)
Count the number of deque elements equal to *x*.
.. versionadded:: 3.2
.. method:: extend(iterable) .. method:: extend(iterable)
Extend the right side of the deque by appending elements from the iterable Extend the right side of the deque by appending elements from the iterable

View file

@ -114,6 +114,30 @@ class TestBasic(unittest.TestCase):
d = deque('abc') d = deque('abc')
d.maxlen = 10 d.maxlen = 10
def test_count(self):
for s in ('', 'abracadabra', 'simsalabim'*500+'abc'):
s = list(s)
d = deque(s)
for letter in 'abcdefghijklmnopqrstuvwxyz':
self.assertEqual(s.count(letter), d.count(letter), (s, d, letter))
self.assertRaises(TypeError, d.count) # too few args
self.assertRaises(TypeError, d.count, 1, 2) # too many args
class BadCompare:
def __eq__(self, other):
raise ArithmeticError
d = deque([1, 2, BadCompare(), 3])
self.assertRaises(ArithmeticError, d.count, 2)
d = deque([1, 2, 3])
self.assertRaises(ArithmeticError, d.count, BadCompare())
class MutatingCompare:
def __eq__(self, other):
self.d.pop()
return True
m = MutatingCompare()
d = deque([1, 2, 3, m, 4, 5])
m.d = d
self.assertRaises(RuntimeError, d.count, 3)
def test_comparisons(self): def test_comparisons(self):
d = deque('xabc'); d.popleft() d = deque('xabc'); d.popleft()
for e in [d, deque('abc'), deque('ab'), deque(), list(d)]: for e in [d, deque('abc'), deque('ab'), deque(), list(d)]:

View file

@ -576,7 +576,7 @@ Library
- Issue #5949: added check for correct lineends in input from IMAP server - Issue #5949: added check for correct lineends in input from IMAP server
in imaplib. in imaplib.
- Add a reverse() method to collections.deque(). - Add count() and reverse() methods to collections.deque().
- Fix variations of extending deques: d.extend(d) d.extendleft(d) d+=d - Fix variations of extending deques: d.extend(d) d.extendleft(d) d+=d

View file

@ -504,6 +504,46 @@ deque_reverse(dequeobject *deque, PyObject *unused)
PyDoc_STRVAR(reverse_doc, PyDoc_STRVAR(reverse_doc,
"D.reverse() -- reverse *IN PLACE*"); "D.reverse() -- reverse *IN PLACE*");
static PyObject *
deque_count(dequeobject *deque, PyObject *v)
{
block *leftblock = deque->leftblock;
Py_ssize_t leftindex = deque->leftindex;
Py_ssize_t n = (deque->len);
Py_ssize_t i;
Py_ssize_t count = 0;
PyObject *item;
long start_state = deque->state;
int cmp;
for (i=0 ; i<n ; i++) {
item = leftblock->data[leftindex];
cmp = PyObject_RichCompareBool(item, v, Py_EQ);
if (cmp > 0)
count++;
else if (cmp < 0)
return NULL;
if (start_state != deque->state) {
PyErr_SetString(PyExc_RuntimeError,
"deque mutated during iteration");
return NULL;
}
/* Advance left block/index pair */
leftindex++;
if (leftindex == BLOCKLEN) {
assert (leftblock->rightlink != NULL);
leftblock = leftblock->rightlink;
leftindex = 0;
}
}
return PyLong_FromSsize_t(count);
}
PyDoc_STRVAR(count_doc,
"D.count(value) -> integer -- return number of occurrences of value");
static Py_ssize_t static Py_ssize_t
deque_len(dequeobject *deque) deque_len(dequeobject *deque)
{ {
@ -933,6 +973,8 @@ static PyMethodDef deque_methods[] = {
METH_NOARGS, clear_doc}, METH_NOARGS, clear_doc},
{"__copy__", (PyCFunction)deque_copy, {"__copy__", (PyCFunction)deque_copy,
METH_NOARGS, copy_doc}, METH_NOARGS, copy_doc},
{"count", (PyCFunction)deque_count,
METH_O, count_doc},
{"extend", (PyCFunction)deque_extend, {"extend", (PyCFunction)deque_extend,
METH_O, extend_doc}, METH_O, extend_doc},
{"extendleft", (PyCFunction)deque_extendleft, {"extendleft", (PyCFunction)deque_extendleft,