Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make slice deletion consistent with standard lists, fixes #12 #14

Merged
merged 7 commits into from
Aug 4, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
language: python
python:
- 2.7
- 3.3
- 3.4
- 3.5
- 3.6
- 3.7-dev
- 3.7
- nightly
- pypy
install: pip install -r requirements.txt
Expand Down
23 changes: 17 additions & 6 deletions sparse_list.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,14 +69,26 @@ def __setslice__(self, start, stop, vals):
def __delitem__(self, item):
if isinstance(item, slice):
indices = xrange(*item.indices(self.size))
elif item < 0:
indices = (self.size + item, )
else:
indices = (item, )

for i in indices:
try:
del self.elements[i]
except KeyError:
pass
offset = 0

for k in sorted(self.elements.keys()):
if k < indices[0]:
continue
elif offset < len(indices) and k > indices[offset]:
offset += 1

if offset:
self.elements[k - offset] = self.elements[k]

del self.elements[k]

self.size -= len(indices)


def __delslice__(self, start, stop):
'''
Expand Down Expand Up @@ -184,7 +196,6 @@ def pop(self):
raise IndexError('pop from empty SparseList')
value = self[-1]
del self[-1]
self.size -= 1
return value

def remove(self, value):
Expand Down
22 changes: 11 additions & 11 deletions test_sparse_list.py
Original file line number Diff line number Diff line change
Expand Up @@ -141,32 +141,32 @@ def test_set_out_of_bounds(self):
def test_present_item_removal(self):
sl = sparse_list.SparseList({0: 1, 4: 1}, 0)
del sl[0]
self.assertEqual([0, 0, 0, 0, 1], sl)
self.assertEqual([0, 0, 0, 1], sl)

def test_missing_item_removal(self):
sl = sparse_list.SparseList({0: 1, 4: 1}, 0)
del sl[1]
self.assertEqual([1, 0, 0, 0, 1], sl)
self.assertEqual([1, 0, 0, 1], sl)

def test_slice_removal(self):
sl = sparse_list.SparseList(xrange(10), None)
del sl[3:5]
self.assertEqual([0, 1, 2, None, None, 5, 6, 7, 8, 9], sl)
self.assertEqual([0, 1, 2, 5, 6, 7, 8, 9], sl)

def test_unbounded_head_slice_removal(self):
sl = sparse_list.SparseList(xrange(10), None)
del sl[:3]
self.assertEqual([None, None, None, 3, 4, 5, 6, 7, 8, 9], sl)
self.assertEqual([3, 4, 5, 6, 7, 8, 9], sl)

def test_unbounded_tail_slice_removal(self):
sl = sparse_list.SparseList(xrange(10), None)
del sl[5:]
self.assertEqual([0, 1, 2, 3, 4, None, None, None, None, None], sl)
self.assertEqual([0, 1, 2, 3, 4], sl)

def test_stepped_slice_removal(self):
sl = sparse_list.SparseList(xrange(6), None)
del sl[::2]
self.assertEqual([None, 1, None, 3, None, 5], sl)
self.assertEqual([1, 3, 5], sl)

def test_append(self):
sl = sparse_list.SparseList(1, 0)
Expand Down Expand Up @@ -330,23 +330,23 @@ def test_remove_default_value_does_nothing(self):
def test_set_slice_observes_stop(self):
sl = sparse_list.SparseList(4, None)
sl[0:2] = [1, 2, 3]
self.assertEquals([1, 2, None, None], sl)
self.assertEqual([1, 2, None, None], sl)

def test_set_slice_resizes(self):
sl = sparse_list.SparseList(0, None)
sl[4:] = [4, 5]
self.assertEquals([None, None, None, None, 4, 5], sl)
self.assertEquals(len(sl), 6)
self.assertEqual([None, None, None, None, 4, 5], sl)
self.assertEqual(len(sl), 6)

def test_set_slice_extends_past_end(self):
sl = sparse_list.SparseList(5, None)
sl[3:] = [6, 7, 8]
self.assertEquals([None, None, None, 6, 7, 8], sl)
self.assertEqual([None, None, None, 6, 7, 8], sl)

def test_set_slice_with_step(self):
sl = sparse_list.SparseList(6, None)
sl[::2] = [1, 2, 3]
self.assertEquals([1, None, 2, None, 3, None], sl)
self.assertEqual([1, None, 2, None, 3, None], sl)

if __name__ == '__main__':
unittest.main()
22 changes: 22 additions & 0 deletions time_sparse_list.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,5 +37,27 @@ def test_sparse_list(self):
def test_list(self):
self.list[100]

class Benchmark_Slice_Deletion(benchmark.Benchmark):
def setUp(self):
self.sparse_list = sparse_list.SparseList(xrange(1000))
self.list = list(xrange(1000))

def test_sparse_list(self):
del self.sparse_list[1::2]

def test_list(self):
del self.list[1::2]

class Benchmark_Deletion(benchmark.Benchmark):
def setUp(self):
self.sparse_list = sparse_list.SparseList(xrange(1000))
self.list = list(xrange(1000))

def test_sparse_list(self):
del self.sparse_list[100]

def test_list(self):
del self.list[100]

if __name__ == '__main__':
benchmark.main(format="markdown", numberFormat="%.4g")