Kaydet (Commit) 0e371f2c authored tarafından Raymond Hettinger's avatar Raymond Hettinger

Make sure "del d[n]" is properly supported. Was necessary because the

same method that implements __setitem__ also implements __delitem__.
Also, there were several good use cases (removing items from a queue
and implementing Forth style stack ops).
üst fd3f4fb7
...@@ -137,24 +137,21 @@ This section shows various approaches to working with deques. ...@@ -137,24 +137,21 @@ This section shows various approaches to working with deques.
The \method{rotate()} method provides a way to implement \class{deque} The \method{rotate()} method provides a way to implement \class{deque}
slicing and deletion: slicing and deletion:
This pure python implementation of \code{del d[n]} shows how to use the
\method{rotate()} method as a building block for implementing a variety
of class{deque} operations:
\begin{verbatim} \begin{verbatim}
def delete_nth(d, n): def delete_nth(d, n):
"del d[n]"
d.rotate(-n) d.rotate(-n)
d.popleft() d.popleft()
d.rotate(n) d.rotate(n)
>>> d = deque('abcdef')
>>> delete_nth(d, 2) # remove the entry at d[2]
>>> d
deque(['a', 'b', 'd', 'e', 'f'])
\end{verbatim} \end{verbatim}
For slicing, the idea is the same. Use \method{rotate()} to bring a target To implement \class{deque} slicing, use a similar approach applying
element to the left side of the deque. Remove old entries with \method{rotate()} to bring a target element to the left side of the deque.
\method{popleft()}, add new entries with \method{extend()}, and then Remove old entries with \method{popleft()}, add new entries with
reverse the rotation. \method{extend()}, and then reverse the rotation.
With minor variations on that approach, it is easy to implement Forth style With minor variations on that approach, it is easy to implement Forth style
stack manipulations such as \code{dup}, \code{drop}, \code{swap}, \code{over}, stack manipulations such as \code{dup}, \code{drop}, \code{swap}, \code{over},
......
...@@ -90,6 +90,20 @@ class TestBasic(unittest.TestCase): ...@@ -90,6 +90,20 @@ class TestBasic(unittest.TestCase):
l[i] = 7*i l[i] = 7*i
self.assertEqual(list(d), l) self.assertEqual(list(d), l)
def test_delitem(self):
n = 500 # O(n**2) test, don't make this too big
d = deque(xrange(n))
self.assertRaises(IndexError, d.__delitem__, -n-1)
self.assertRaises(IndexError, d.__delitem__, n)
for i in xrange(n):
self.assertEqual(len(d), n-i)
j = random.randrange(-len(d), len(d))
val = d[j]
self.assert_(val in d)
del d[j]
self.assert_(val not in d)
self.assertEqual(len(d), 0)
def test_rotate(self): def test_rotate(self):
s = tuple('abcde') s = tuple('abcde')
n = len(s) n = len(s)
...@@ -476,9 +490,7 @@ deque(['c', 'b', 'a']) ...@@ -476,9 +490,7 @@ deque(['c', 'b', 'a'])
>>> def delete_nth(d, n): >>> def delete_nth(d, n):
... "del d[n]"
... d.rotate(-n) ... d.rotate(-n)
... d.popleft() ... d.popleft()
... d.rotate(n) ... d.rotate(n)
...@@ -524,7 +536,6 @@ h ...@@ -524,7 +536,6 @@ h
>>> print maketree('abcdefgh') >>> print maketree('abcdefgh')
[[[['a', 'b'], ['c', 'd']], [['e', 'f'], ['g', 'h']]]] [[[['a', 'b'], ['c', 'd']], [['e', 'f'], ['g', 'h']]]]
""" """
......
...@@ -352,6 +352,44 @@ deque_item(dequeobject *deque, int i) ...@@ -352,6 +352,44 @@ deque_item(dequeobject *deque, int i)
return item; return item;
} }
static int
deque_del_item(dequeobject *deque, int i)
{
PyObject *item=NULL, *minus_i=NULL, *plus_i=NULL;
int rv = -1;
assert (i >= 0 && i < deque->len);
minus_i = Py_BuildValue("(i)", -i);
if (minus_i == NULL)
goto fail;
plus_i = Py_BuildValue("(i)", i);
if (plus_i == NULL)
goto fail;
item = deque_rotate(deque, minus_i);
if (item == NULL)
goto fail;
Py_DECREF(item);
item = deque_popleft(deque, NULL);
if (item == NULL)
goto fail;
Py_DECREF(item);
item = deque_rotate(deque, plus_i);
if (item == NULL)
goto fail;
rv = 0;
fail:
Py_XDECREF(item);
Py_XDECREF(minus_i);
Py_XDECREF(plus_i);
return rv;
}
static int static int
deque_ass_item(dequeobject *deque, int i, PyObject *v) deque_ass_item(dequeobject *deque, int i, PyObject *v)
{ {
...@@ -364,6 +402,9 @@ deque_ass_item(dequeobject *deque, int i, PyObject *v) ...@@ -364,6 +402,9 @@ deque_ass_item(dequeobject *deque, int i, PyObject *v)
"deque index out of range"); "deque index out of range");
return -1; return -1;
} }
if (v == NULL)
return deque_del_item(deque, i);
i += deque->leftindex; i += deque->leftindex;
n = i / BLOCKLEN; n = i / BLOCKLEN;
i %= BLOCKLEN; i %= BLOCKLEN;
......
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