Commit 44459deb authored by Raymond Hettinger's avatar Raymond Hettinger

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

parent 4893abc7
...@@ -338,6 +338,12 @@ counts, but the output will exclude results with counts of zero or less. ...@@ -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
......
...@@ -114,6 +114,30 @@ class TestBasic(unittest.TestCase): ...@@ -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)]:
......
...@@ -576,7 +576,7 @@ Library ...@@ -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
......
...@@ -504,6 +504,46 @@ deque_reverse(dequeobject *deque, PyObject *unused) ...@@ -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[] = { ...@@ -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,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment