Using the iterator protocol

======================

Loop through the iterator, skip the items in iterator until an item that does not match the skip_value is found.


In [3]:
def lstrip(iterable, strip_value):
    """ Return iterable with strip_value removed from the beginnning"""
    stripped = []
    iterator = iter(iterable)
    for item in iterator:
        if not item == strip_value:
            stripped.append(item)
            break
            
    for item in iterator:
        stripped.append(item)
        
    return stripped

In [4]:
import unittest

class LStripTests(unittest.TestCase):

    """Tests for lstrip."""

    def assertIterableEqual(self, iterable1, iterable2):
        self.assertEqual(list(iterable1), list(iterable2))

    def test_list(self):
        self.assertIterableEqual(lstrip([1, 1, 2, 3], 1), [2, 3])

    def test_nothing_to_strip(self):
        self.assertIterableEqual(lstrip([1, 2, 3], 0), [1, 2, 3])

    def test_string(self):
        self.assertIterableEqual(lstrip('  hello', ' '), 'hello')

    def test_empty_iterable(self):
        self.assertIterableEqual(lstrip([], 1), [])

    def test_strip_all(self):
        self.assertIterableEqual(lstrip([1, 1, 1], 1), [])

    def test_none_values(self):
        self.assertIterableEqual(lstrip([None, 1, 2, 3], 0), [None, 1, 2, 3])

    def test_iterator(self):
        squares = (n**2 for n in [0, 0, 1, 2, 3])
        self.assertIterableEqual(lstrip(squares, 0), [1, 4, 9])

    # To test the Bonus part of this exercise, comment out the following line
    @unittest.expectedFailure
    def test_returns_iterator(self):
        stripped = lstrip((1, 2, 3), 1)
        self.assertEqual(iter(stripped), iter(stripped))

    # To test the Bonus part of this exercise, comment out the following line
    @unittest.expectedFailure
    def test_function_given(self):
        numbers = [0, 2, 4, 1, 3, 5, 6]
        def is_even(n): return n % 2 == 0
        self.assertIterableEqual(lstrip(numbers, is_even), [1, 3, 5, 6])


if __name__ == "__main__":
    unittest.main(argv=['ignore-first-arg'], exit=False)


.x....x..
----------------------------------------------------------------------
Ran 9 tests in 0.004s

OK (expected failures=2)

Bonus1: The lstrip function should return an iterator


In [5]:
def lstrip(iterable, strip_value):
    """ Return iterable with strip_value removed from the beginnning"""
    iterator = iter(iterable)
    for item in iterator:
        if not item == strip_value:
            yield item
            break
            
    for item in iterator:
        yield item

In [7]:
import unittest

class LStripTests(unittest.TestCase):

    """Tests for lstrip."""

    def assertIterableEqual(self, iterable1, iterable2):
        self.assertEqual(list(iterable1), list(iterable2))

    def test_list(self):
        self.assertIterableEqual(lstrip([1, 1, 2, 3], 1), [2, 3])

    def test_nothing_to_strip(self):
        self.assertIterableEqual(lstrip([1, 2, 3], 0), [1, 2, 3])

    def test_string(self):
        self.assertIterableEqual(lstrip('  hello', ' '), 'hello')

    def test_empty_iterable(self):
        self.assertIterableEqual(lstrip([], 1), [])

    def test_strip_all(self):
        self.assertIterableEqual(lstrip([1, 1, 1], 1), [])

    def test_none_values(self):
        self.assertIterableEqual(lstrip([None, 1, 2, 3], 0), [None, 1, 2, 3])

    def test_iterator(self):
        squares = (n**2 for n in [0, 0, 1, 2, 3])
        self.assertIterableEqual(lstrip(squares, 0), [1, 4, 9])

    # To test the Bonus part of this exercise, comment out the following line
    # @unittest.expectedFailure
    def test_returns_iterator(self):
        stripped = lstrip((1, 2, 3), 1)
        self.assertEqual(iter(stripped), iter(stripped))

    # To test the Bonus part of this exercise, comment out the following line
    @unittest.expectedFailure
    def test_function_given(self):
        numbers = [0, 2, 4, 1, 3, 5, 6]
        def is_even(n): return n % 2 == 0
        self.assertIterableEqual(lstrip(numbers, is_even), [1, 3, 5, 6])


if __name__ == "__main__":
    unittest.main(argv=['ignore-first-arg'], exit=False)


.x.......
----------------------------------------------------------------------
Ran 9 tests in 0.003s

OK (expected failures=1)

Experiments : Testing iterator


In [9]:
my_list = [1, 2, 3, 4]
iterator1 = iter(my_list)
iterator2 = iter(my_list)
iterator1 == iterator2


Out[9]:
False

In [11]:
my_list = [1, 2, 3, 4]
iterator = iter(my_list)
iterator1 = iter(iterator)
iterator2 = iter(iterator)
iterator1 == iterator2


Out[11]:
True

Bonus2: We're supposed to optionally accept a function as our strip value and call that function to determine whether values should be removed


In [1]:
def lstrip(iterable, strip_value):
    """Return iterable with strip_value items removed from beginning."""
    iterator = iter(iterable)
    for item in iterator:
        if (callable(strip_value) and not strip_value(item)
                or item != strip_value):
            yield item
            break
    for item in iterator:
        yield item

In [2]:
import unittest

class LStripTests(unittest.TestCase):

    """Tests for lstrip."""

    def assertIterableEqual(self, iterable1, iterable2):
        self.assertEqual(list(iterable1), list(iterable2))

    def test_list(self):
        self.assertIterableEqual(lstrip([1, 1, 2, 3], 1), [2, 3])

    def test_nothing_to_strip(self):
        self.assertIterableEqual(lstrip([1, 2, 3], 0), [1, 2, 3])

    def test_string(self):
        self.assertIterableEqual(lstrip('  hello', ' '), 'hello')

    def test_empty_iterable(self):
        self.assertIterableEqual(lstrip([], 1), [])

    def test_strip_all(self):
        self.assertIterableEqual(lstrip([1, 1, 1], 1), [])

    def test_none_values(self):
        self.assertIterableEqual(lstrip([None, 1, 2, 3], 0), [None, 1, 2, 3])

    def test_iterator(self):
        squares = (n**2 for n in [0, 0, 1, 2, 3])
        self.assertIterableEqual(lstrip(squares, 0), [1, 4, 9])

    # To test the Bonus part of this exercise, comment out the following line
    # @unittest.expectedFailure
    def test_returns_iterator(self):
        stripped = lstrip((1, 2, 3), 1)
        self.assertEqual(iter(stripped), iter(stripped))

    # To test the Bonus part of this exercise, comment out the following line
    # @unittest.expectedFailure
    def test_function_given(self):
        numbers = [0, 2, 4, 1, 3, 5, 6]
        def is_even(n): return n % 2 == 0
        self.assertIterableEqual(lstrip(numbers, is_even), [1, 3, 5, 6])


if __name__ == "__main__":
    unittest.main(argv=['ignore-first-arg'], exit=False)


.F.......
======================================================================
FAIL: test_function_given (__main__.LStripTests)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "<ipython-input-2-1549a645be69>", line 43, in test_function_given
    self.assertIterableEqual(lstrip(numbers, is_even), [1, 3, 5, 6])
  File "<ipython-input-2-1549a645be69>", line 8, in assertIterableEqual
    self.assertEqual(list(iterable1), list(iterable2))
AssertionError: Lists differ: [0, 2, 4, 1, 3, 5, 6] != [1, 3, 5, 6]

First differing element 0:
0
1

First list contains 3 additional elements.
First extra element 4:
3

- [0, 2, 4, 1, 3, 5, 6]
+ [1, 3, 5, 6]

----------------------------------------------------------------------
Ran 9 tests in 0.004s

FAILED (failures=1)

In [14]:
def lstrip(iterable, strip_value):
    """Return iterable with strip_value items removed from beginning."""
    iterator = iter(iterable)
    if callable(strip_value):
        predicate = strip_value
    else:
        def predicate(value): return value == strip_value
        
    for item in iterator:
        if not predicate(item):
            yield item
            break
    for item in iterator:
        yield item

In [15]:
import unittest

class LStripTests(unittest.TestCase):

    """Tests for lstrip."""

    def assertIterableEqual(self, iterable1, iterable2):
        self.assertEqual(list(iterable1), list(iterable2))

    def test_list(self):
        self.assertIterableEqual(lstrip([1, 1, 2, 3], 1), [2, 3])

    def test_nothing_to_strip(self):
        self.assertIterableEqual(lstrip([1, 2, 3], 0), [1, 2, 3])

    def test_string(self):
        self.assertIterableEqual(lstrip('  hello', ' '), 'hello')

    def test_empty_iterable(self):
        self.assertIterableEqual(lstrip([], 1), [])

    def test_strip_all(self):
        self.assertIterableEqual(lstrip([1, 1, 1], 1), [])

    def test_none_values(self):
        self.assertIterableEqual(lstrip([None, 1, 2, 3], 0), [None, 1, 2, 3])

    def test_iterator(self):
        squares = (n**2 for n in [0, 0, 1, 2, 3])
        self.assertIterableEqual(lstrip(squares, 0), [1, 4, 9])

    # To test the Bonus part of this exercise, comment out the following line
    # @unittest.expectedFailure
    def test_returns_iterator(self):
        stripped = lstrip((1, 2, 3), 1)
        self.assertEqual(iter(stripped), iter(stripped))

    # To test the Bonus part of this exercise, comment out the following line
    # @unittest.expectedFailure
    def test_function_given(self):
        numbers = [0, 2, 4, 1, 3, 5, 6]
        def is_even(n): return n % 2 == 0
        self.assertIterableEqual(lstrip(numbers, is_even), [1, 3, 5, 6])


if __name__ == "__main__":
    unittest.main(argv=['ignore-first-arg'], exit=False)


.........
----------------------------------------------------------------------
Ran 9 tests in 0.015s

OK

Using dropwhile helper function in itertools module

========================================

The dropwhile function in the itertools module will give us an iterable that has our original iterable's values except it drops any at the beginning that pass a certain test.

Bonus1: The lstrip function should return an iterator


In [1]:
from itertools import dropwhile
def lstrip(iterable, strip_value):
    """Return iterable with strip_value items removed from beginning."""
    def is_strip_value(item): return item == strip_value
    
    return dropwhile(is_strip_value, iterable)

In [2]:
import unittest

class LStripTests(unittest.TestCase):

    """Tests for lstrip."""

    def assertIterableEqual(self, iterable1, iterable2):
        self.assertEqual(list(iterable1), list(iterable2))

    def test_list(self):
        self.assertIterableEqual(lstrip([1, 1, 2, 3], 1), [2, 3])

    def test_nothing_to_strip(self):
        self.assertIterableEqual(lstrip([1, 2, 3], 0), [1, 2, 3])

    def test_string(self):
        self.assertIterableEqual(lstrip('  hello', ' '), 'hello')

    def test_empty_iterable(self):
        self.assertIterableEqual(lstrip([], 1), [])

    def test_strip_all(self):
        self.assertIterableEqual(lstrip([1, 1, 1], 1), [])

    def test_none_values(self):
        self.assertIterableEqual(lstrip([None, 1, 2, 3], 0), [None, 1, 2, 3])

    def test_iterator(self):
        squares = (n**2 for n in [0, 0, 1, 2, 3])
        self.assertIterableEqual(lstrip(squares, 0), [1, 4, 9])

    # To test the Bonus part of this exercise, comment out the following line
    # @unittest.expectedFailure
    def test_returns_iterator(self):
        stripped = lstrip((1, 2, 3), 1)
        self.assertEqual(iter(stripped), iter(stripped))

    # To test the Bonus part of this exercise, comment out the following line
    @unittest.expectedFailure
    def test_function_given(self):
        numbers = [0, 2, 4, 1, 3, 5, 6]
        def is_even(n): return n % 2 == 0
        self.assertIterableEqual(lstrip(numbers, is_even), [1, 3, 5, 6])


if __name__ == "__main__":
    unittest.main(argv=['ignore-first-arg'], exit=False)


.x.......
----------------------------------------------------------------------
Ran 9 tests in 0.007s

OK (expected failures=1)

Bonus2: We're supposed to optionally accept a function as our strip value and call that function to determine whether values should be removed


In [3]:
from itertools import dropwhile
def lstrip(iterable, strip_value):
    """Return iterable with strip_value items removed from beginning."""
    if callable(strip_value):
        predicate = strip_value
    else:
        def predicate(item): return item == strip_value
        
    return dropwhile(predicate, iterable)

In [4]:
import unittest

class LStripTests(unittest.TestCase):

    """Tests for lstrip."""

    def assertIterableEqual(self, iterable1, iterable2):
        self.assertEqual(list(iterable1), list(iterable2))

    def test_list(self):
        self.assertIterableEqual(lstrip([1, 1, 2, 3], 1), [2, 3])

    def test_nothing_to_strip(self):
        self.assertIterableEqual(lstrip([1, 2, 3], 0), [1, 2, 3])

    def test_string(self):
        self.assertIterableEqual(lstrip('  hello', ' '), 'hello')

    def test_empty_iterable(self):
        self.assertIterableEqual(lstrip([], 1), [])

    def test_strip_all(self):
        self.assertIterableEqual(lstrip([1, 1, 1], 1), [])

    def test_none_values(self):
        self.assertIterableEqual(lstrip([None, 1, 2, 3], 0), [None, 1, 2, 3])

    def test_iterator(self):
        squares = (n**2 for n in [0, 0, 1, 2, 3])
        self.assertIterableEqual(lstrip(squares, 0), [1, 4, 9])

    # To test the Bonus part of this exercise, comment out the following line
    # @unittest.expectedFailure
    def test_returns_iterator(self):
        stripped = lstrip((1, 2, 3), 1)
        self.assertEqual(iter(stripped), iter(stripped))

    # To test the Bonus part of this exercise, comment out the following line
    # @unittest.expectedFailure
    def test_function_given(self):
        numbers = [0, 2, 4, 1, 3, 5, 6]
        def is_even(n): return n % 2 == 0
        self.assertIterableEqual(lstrip(numbers, is_even), [1, 3, 5, 6])


if __name__ == "__main__":
    unittest.main(argv=['ignore-first-arg'], exit=False)


.........
----------------------------------------------------------------------
Ran 9 tests in 0.003s

OK

In [ ]: