Please review unique_list
:
unique_list
implements a list
where all items are unique. Functionality can also be described as set
with order. unique_list
should behave as a python list
except:
- Adding items the end of the list (by
append
,extend
) will do nothing if the item is already in the list. - Assigning to the middle of the list (
insert
,__setitem__
) will remove previous item with the same value - if any.
class unique_list(list):
def __init__(self, initial_list = ()):
super(unique_list, self).__init__()
self.attendance = set()
self.extend(initial_list)
def __setitem__(self, index, item):
prev_item = self[index]
if prev_item != item:
if item in self.attendance:
prev_index_for_item = self.index(item)
super(unique_list, self).__setitem__(index, item)
del self[prev_index_for_item]
self.attendance.add(item)
else:
super(unique_list, self).__setitem__(index, item)
self.attendance.add(item)
def __delitem__(self, index):
super(unique_list, self).__delitem__(index)
self.attendance.remove(self[index])
def __contains__(self, item):
""" Overriding __contains__ is not required - just more efficient """
return item in self.attendance
def append(self, item):
if item not in self.attendance:
super(unique_list, self).append(item)
self.attendance.add(item)
def extend(self, items = ()):
for item in items:
if item not in self.attendance:
super(unique_list, self).append(item)
self.attendance.add(item)
def insert(self, index, item):
if item in self.attendance:
prev_index_for_item = self.index(item)
if index != prev_index_for_item:
super(unique_list, self).insert(index, item)
if prev_index_for_item < index:
super(unique_list, self).__delitem__(prev_index_for_item)
else:
super(unique_list, self).__delitem__(prev_index_for_item+1)
else:
super(unique_list, self).insert(index, item)
self.attendance.add(item)
def remove(self, item):
if item in self.attendance:
super(unique_list, self).remove(item)
self.attendance.remove(item)
def pop(self, index=-1):
self.attendance.remove(self[index])
return super(unique_list, self).pop(index)
def count(self, item):
""" Overriding count is not required - just more efficient """
return self.attendance.count(item)
Here is my final (as of now) version:
class unique_list(list):
__slots__ = ('__attendance',)
def __init__(self, initial_list = ()):
super(unique_list, self).__init__()
self.__attendance = set()
self.extend(initial_list)
def __setitem__(self, index, item):
prev_item = self[index]
if prev_item != item:
if item in self.__attendance:
prev_index_for_item = self.index(item)
super(unique_list, self).__setitem__(index, item)
del self[prev_index_for_item]
self.__attendance.add(item)
else:
super(unique_list, self).__setitem__(index, item)
self.__attendance.remove(prev_item)
self.__attendance.add(item)
def __delitem__(self, index):
super(unique_list, self).__delitem__(index)
self.__attendance.remove(self[index])
def __contains__(self, item):
""" Overriding __contains__ is not required - just more efficient """
return item in self.__attendance
def append(self, item):
if item not in self.__attendance:
super(unique_list, self).append(item)
self.__attendance.add(item)
def extend(self, items = ()):
for item in items:
if item not in self.__attendance:
super(unique_list, self).append(item)
self.__attendance.add(item)
def insert(self, index, item):
if item in self.__attendance:
prev_index_for_item = self.index(item)
if index != prev_index_for_item:
super(unique_list, self).insert(index, item)
if prev_index_for_item < index:
super(unique_list, self).__delitem__(prev_index_for_item)
else:
super(unique_list, self).__delitem__(prev_index_for_item+1)
else:
super(unique_list, self).insert(index, item)
self.__attendance.add(item)
def remove(self, item):
if item in self.__attendance:
super(unique_list, self).remove(item)
self.__attendance.remove(item)
def pop(self, index=-1):
self.__attendance.remove(self[index])
return super(unique_list, self).pop(index)
def count(self, item):
""" Overriding count is not required - just more efficient """
return self.__attendance.count(item)
OrderedSet
recipe. – Gareth Rees Feb 25 '13 at 20:34