In [1]:
def uniques_only(iterable):
"""
Returns an iterable in the same order with duplicates removed
"""
seen = set()
for item in iterable:
if item not in seen:
yield item
seen.add(item)
In [3]:
from timeit import default_timer
import unittest
class UniquesOnlyTests(unittest.TestCase):
"""Tests for uniques_only."""
def assertIterableEqual(self, iterable1, iterable2):
self.assertEqual(list(iterable1), list(iterable2))
def test_no_duplicates(self):
self.assertIterableEqual(uniques_only([1, 2, 3]), [1, 2, 3])
def test_adjacent_duplicates(self):
self.assertIterableEqual(uniques_only([1, 1, 2, 2, 3]), [1, 2, 3])
def test_non_adjacent_duplicates(self):
self.assertIterableEqual(uniques_only([1, 2, 3, 1, 2]), [1, 2, 3])
def test_lots_of_duplicates(self):
self.assertIterableEqual(uniques_only([1, 2, 2, 1, 1, 2, 1]), [1, 2])
def test_accepts_iterator(self):
nums = (n**2 for n in [1, 2, 3])
self.assertIterableEqual(uniques_only(nums), [1, 4, 9])
# To test the Bonus part of this exercise, comment out the following line
# @unittest.expectedFailure
def test_returns_iterator(self):
nums = iter([1, 2, 3])
output = uniques_only(nums)
self.assertEqual(iter(output), iter(output))
self.assertEqual(next(output), 1)
self.assertEqual(next(nums), 2)
# To test the Bonus part of this exercise, comment out the following line
# @unittest.expectedFailure
def test_accepts_nonhashable_types(self):
output = uniques_only([[1, 2], [3], [1], [3]])
self.assertIterableEqual(output, [[1, 2], [3], [1]])
# To test the Bonus part of this exercise, comment out the following line
# @unittest.expectedFailure
def test_hashable_types_faster(self):
hashables = [(n,) for n in range(4000)] + [0]
unhashables = [[n] for n in range(4000)] + [0]
with Timer() as hashable:
for _ in uniques_only(hashables):
pass
with Timer() as unhashable:
for _ in uniques_only(unhashables):
pass
self.assertLess(hashable.elapsed * 5, unhashable.elapsed)
class Timer:
"""Context manager to time a code block."""
def __enter__(self):
self.start = default_timer()
return self
def __exit__(self, *args):
self.end = default_timer()
self.elapsed = self.end - self.start
if __name__ == "__main__":
unittest.main(argv=['ignore-first-argument'], exit=False)
In [4]:
tmp = set()
In [5]:
1 in tmp
Out[5]:
In [6]:
[1] in tmp
In [8]:
tmp.add(1)
tmp
Out[8]:
In [9]:
tmp.add([1])
In [11]:
tmp = set([1])
tmp
Out[11]:
In [14]:
def uniques_only(iterable):
"""
Returns an iterable in the same order with duplicates removed
"""
seen = []
for item in iterable:
if item not in seen:
yield item
seen.append(item)
In [15]:
from timeit import default_timer
import unittest
class UniquesOnlyTests(unittest.TestCase):
"""Tests for uniques_only."""
def assertIterableEqual(self, iterable1, iterable2):
self.assertEqual(list(iterable1), list(iterable2))
def test_no_duplicates(self):
self.assertIterableEqual(uniques_only([1, 2, 3]), [1, 2, 3])
def test_adjacent_duplicates(self):
self.assertIterableEqual(uniques_only([1, 1, 2, 2, 3]), [1, 2, 3])
def test_non_adjacent_duplicates(self):
self.assertIterableEqual(uniques_only([1, 2, 3, 1, 2]), [1, 2, 3])
def test_lots_of_duplicates(self):
self.assertIterableEqual(uniques_only([1, 2, 2, 1, 1, 2, 1]), [1, 2])
def test_accepts_iterator(self):
nums = (n**2 for n in [1, 2, 3])
self.assertIterableEqual(uniques_only(nums), [1, 4, 9])
# To test the Bonus part of this exercise, comment out the following line
# @unittest.expectedFailure
def test_returns_iterator(self):
nums = iter([1, 2, 3])
output = uniques_only(nums)
self.assertEqual(iter(output), iter(output))
self.assertEqual(next(output), 1)
self.assertEqual(next(nums), 2)
# To test the Bonus part of this exercise, comment out the following line
# @unittest.expectedFailure
def test_accepts_nonhashable_types(self):
output = uniques_only([[1, 2], [3], [1], [3]])
self.assertIterableEqual(output, [[1, 2], [3], [1]])
# To test the Bonus part of this exercise, comment out the following line
# @unittest.expectedFailure
def test_hashable_types_faster(self):
hashables = [(n,) for n in range(4000)] + [0]
unhashables = [[n] for n in range(4000)] + [0]
with Timer() as hashable:
for _ in uniques_only(hashables):
pass
with Timer() as unhashable:
for _ in uniques_only(unhashables):
pass
self.assertLess(hashable.elapsed * 5, unhashable.elapsed)
class Timer:
"""Context manager to time a code block."""
def __enter__(self):
self.start = default_timer()
return self
def __exit__(self, *args):
self.end = default_timer()
self.elapsed = self.end - self.start
if __name__ == "__main__":
unittest.main(argv=['ignore-first-argument'], exit=False)
In [16]:
def uniques_only(iterable):
"""
Returns an iterable in the same order with duplicates removed
"""
hashable_seen = set()
unhashable_seen = []
for item in iterable:
try:
if item not in hashable_seen:
yield item
hashable_seen.add(item)
except TypeError:
if item not in unhashable_seen:
yield item
unhashable_seen.append(item)
In [17]:
from timeit import default_timer
import unittest
class UniquesOnlyTests(unittest.TestCase):
"""Tests for uniques_only."""
def assertIterableEqual(self, iterable1, iterable2):
self.assertEqual(list(iterable1), list(iterable2))
def test_no_duplicates(self):
self.assertIterableEqual(uniques_only([1, 2, 3]), [1, 2, 3])
def test_adjacent_duplicates(self):
self.assertIterableEqual(uniques_only([1, 1, 2, 2, 3]), [1, 2, 3])
def test_non_adjacent_duplicates(self):
self.assertIterableEqual(uniques_only([1, 2, 3, 1, 2]), [1, 2, 3])
def test_lots_of_duplicates(self):
self.assertIterableEqual(uniques_only([1, 2, 2, 1, 1, 2, 1]), [1, 2])
def test_accepts_iterator(self):
nums = (n**2 for n in [1, 2, 3])
self.assertIterableEqual(uniques_only(nums), [1, 4, 9])
# To test the Bonus part of this exercise, comment out the following line
# @unittest.expectedFailure
def test_returns_iterator(self):
nums = iter([1, 2, 3])
output = uniques_only(nums)
self.assertEqual(iter(output), iter(output))
self.assertEqual(next(output), 1)
self.assertEqual(next(nums), 2)
# To test the Bonus part of this exercise, comment out the following line
# @unittest.expectedFailure
def test_accepts_nonhashable_types(self):
output = uniques_only([[1, 2], [3], [1], [3]])
self.assertIterableEqual(output, [[1, 2], [3], [1]])
# To test the Bonus part of this exercise, comment out the following line
# @unittest.expectedFailure
def test_hashable_types_faster(self):
hashables = [(n,) for n in range(4000)] + [0]
unhashables = [[n] for n in range(4000)] + [0]
with Timer() as hashable:
for _ in uniques_only(hashables):
pass
with Timer() as unhashable:
for _ in uniques_only(unhashables):
pass
self.assertLess(hashable.elapsed * 5, unhashable.elapsed)
class Timer:
"""Context manager to time a code block."""
def __enter__(self):
self.start = default_timer()
return self
def __exit__(self, *args):
self.end = default_timer()
self.elapsed = self.end - self.start
if __name__ == "__main__":
unittest.main(argv=['ignore-first-argument'], exit=False)
In [21]:
from collections.abc import Hashable
def uniques_only(iterable):
"""
Returns an iterable in the same order with duplicates removed
"""
hashable_seen = set()
unhashable_seen = []
for item in iterable:
if isinstance(item, Hashable):
if item not in hashable_seen:
yield item
hashable_seen.add(item)
else:
if item not in unhashable_seen:
yield item
unhashable_seen.append(item)
In [22]:
from timeit import default_timer
import unittest
class UniquesOnlyTests(unittest.TestCase):
"""Tests for uniques_only."""
def assertIterableEqual(self, iterable1, iterable2):
self.assertEqual(list(iterable1), list(iterable2))
def test_no_duplicates(self):
self.assertIterableEqual(uniques_only([1, 2, 3]), [1, 2, 3])
def test_adjacent_duplicates(self):
self.assertIterableEqual(uniques_only([1, 1, 2, 2, 3]), [1, 2, 3])
def test_non_adjacent_duplicates(self):
self.assertIterableEqual(uniques_only([1, 2, 3, 1, 2]), [1, 2, 3])
def test_lots_of_duplicates(self):
self.assertIterableEqual(uniques_only([1, 2, 2, 1, 1, 2, 1]), [1, 2])
def test_accepts_iterator(self):
nums = (n**2 for n in [1, 2, 3])
self.assertIterableEqual(uniques_only(nums), [1, 4, 9])
# To test the Bonus part of this exercise, comment out the following line
# @unittest.expectedFailure
def test_returns_iterator(self):
nums = iter([1, 2, 3])
output = uniques_only(nums)
self.assertEqual(iter(output), iter(output))
self.assertEqual(next(output), 1)
self.assertEqual(next(nums), 2)
# To test the Bonus part of this exercise, comment out the following line
# @unittest.expectedFailure
def test_accepts_nonhashable_types(self):
output = uniques_only([[1, 2], [3], [1], [3]])
self.assertIterableEqual(output, [[1, 2], [3], [1]])
# To test the Bonus part of this exercise, comment out the following line
# @unittest.expectedFailure
def test_hashable_types_faster(self):
hashables = [(n,) for n in range(4000)] + [0]
unhashables = [[n] for n in range(4000)] + [0]
with Timer() as hashable:
for _ in uniques_only(hashables):
pass
with Timer() as unhashable:
for _ in uniques_only(unhashables):
pass
self.assertLess(hashable.elapsed * 5, unhashable.elapsed)
class Timer:
"""Context manager to time a code block."""
def __enter__(self):
self.start = default_timer()
return self
def __exit__(self, *args):
self.end = default_timer()
self.elapsed = self.end - self.start
if __name__ == "__main__":
unittest.main(argv=['ignore-first-argument'], exit=False)
In [ ]: