In [1]:
def lstrip(iterable, obj):
    stripped = []
    stop = False
    
    for item in iterable:
        if stop:
            stripped.append(item)
        elif item != obj:
            stripped.append(item)
            stop = True
            
    return stripped

In [2]:
lstrip([0, 0, 1, 0, 2, 3], 0)


Out[2]:
[1, 0, 2, 3]

In [3]:
lstrip('  hello ', ' ')


Out[3]:
['h', 'e', 'l', 'l', 'o', ' ']

Bonus1: return an iterator (for example a generator) from your lstrip function instead of a list.


In [8]:
def lstrip(iterable, obj):
    stop = False    
    for item in iterable:
        if stop:
            yield item
        elif item != obj:
            yield item
            stop = True

In [12]:
x = lstrip([0, 1, 2, 3, 0], 0)

In [13]:
x


Out[13]:
<generator object lstrip at 0x0000000004814A40>

In [14]:
list(x)


Out[14]:
[1, 2, 3, 0]

Bonus2: allow your lstrip function to accept a function as its second argument which will determine whether the item should be stripped


In [59]:
def lstrip(iterable, obj):
    lstrip_stop = False    
    for item in iterable:
        if lstrip_stop:
            yield item
        else: 
            if not callable(obj):
                if item != obj:
                    yield item
                    lstrip_stop = True
            else:
                if not obj(item):
                    yield item
                    lstrip_stop = True

In [48]:
def is_falsey(value): return not bool(value)

In [49]:
list(lstrip(['', 0, 1, 0, 2, 'h', ''], is_falsey))


Out[49]:
[1, 0, 2, 'h', '']

In [50]:
list(lstrip([-4, -2, 2, 4, -6], lambda n: n < 0))


Out[50]:
[2, 4, -6]

In [51]:
numbers = [0, 2, 4, 1, 3, 5, 6]

In [52]:
def is_even(n): return n % 2 == 0

In [53]:
list(lstrip(numbers, is_even))


Out[53]:
[1, 3, 5, 6]

In [54]:
list(lstrip([0, 0, 1, 0, 2, 3], 0))


Out[54]:
[1, 0, 2, 3]

In [55]:
list(lstrip('  hello ', ' '))


Out[55]:
['h', 'e', 'l', 'l', 'o', ' ']

Unit Tests


In [60]:
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.004s

OK