 # SortedList Exercise - Sorting on initialisation

HI Folks

So i just completed the Inheritance and polymorphism section in the the CS path.

I’m missing one thing, which is the missing link to me fully understanding this.

I have the following code

class SortedList(list):

def append(self, value):
super().append(value)
self.sort()

m_list = SortedList([4,1,5])
print(m_list)

i now want to adopt it so that when i initialise the instance the list gets sorted straight away.
I have tried a number of things but cant seem to get it to work.

Any suggestions to guide me as to what i am missing?

cheers

`self` is not something we would sort.

Okay, turns out I was wrong in my last statement. `self` is the inherited list object.

As for how to sort the instance I’m at an impasse. The lesson is positively vague. Maybe @appylpye can shed some light on this.

The following was tested with Python 3:

``````class SortedList(list):
def append(self, value):
super().append(value)
self.sort()

a_sorted_list = SortedList([5, 9, 7, 3])

a_sorted_list.append(4)
print(a_sorted_list)
``````

Output:

``````[3, 4, 5, 7, 9]
``````

Within the `append` method included above, the `super` built in function knows to apply the `append` method of `list`, the superclass, to the current instance of `SortedList`.

Then, referring to the current instance as `self`, we can call from it the `sort` method that is inherited from `list`.

Note that we really ought to write an `__init__` method for the `SortedList` class, so that we can put it in sorted condition right from the start. Step 5 does hint at the need for this, and @ byterockstar71616 does ask about this issue.

This statement, placed in the `__init__` method, should take care of that:

``````    self.sort()
``````

The question here is how does one do it without including a constructor?

If you do not include a constructor, wouldn’t you then always begin with an empty `SortedList` object?

1 Like

When I add the constructor the SortedList object is empty.

``````class SortedList(list):
def __init__(self, values):
self.values = sorted(values)
def append(self, value):
super().append(value)
self.sort()

a = SortedList([4, 1, 5])
print (a)
a.append(2)
print (a)
``````

Output

``````[]

``````

The `print` function doesn’t know that it should look at the `values` instance variable, and the `append` method of `SortedList` doesn’t know that it should add the supplied argument to that instance variable either.

We could do it this way:

``````class SortedList(list):
def __init__(self, a_list):
for item in a_list:
self.append(item)
self.sort()
def append(self, value):
super().append(value)
self.sort()
``````
1 Like
``````class SortedList(list):
def __init__(self, values):
self.values = sorted(values)
def append(self, value):
super().append(value)
self.sort()

a = SortedList([4, 1, 5])
print (a.values)
a.append(2)
print (a.values)
``````
``````[1, 4, 5]
[1, 4, 5]
``````

Obviously we cannot construct self else the append method doesn’t work. Trying your suggestion…

I was worried that the initial list would be extended, but it appears it is only overwritten with the same values.

``````[1, 4, 5]
[1, 2, 4, 5]
``````

Thanks for chiming in, @appylpye.

1 Like

If you would like to continue with the `values` instance variable, the following will work, with no need to call the `super` function:

``````class SortedList(list):
def __init__(self, values):
self.values = sorted(values)
def append(self, value):
# replace the following with a more efficient insertion
self.values.append(value)
self.values.sort()
def __repr__(self):
return str(self.values)

a_sorted_list = SortedList([5, 9, 7, 3])
print(a_sorted_list)
a_sorted_list.append(4)
print(a_sorted_list)
``````

Output:

``````[3, 5, 7, 9]
[3, 4, 5, 7, 9]``````

Would we even need to inherit from `list` if this were the case?

1 Like

With this approach, the inheritance would no longer be useful; it is just a relict of the fact that this was part of a lesson in inheritance and polymorphism.

1 Like

On second thought, the inheritance would be useful for identifying an instance of a `SortedList` as a type of `list`. This is so that the user of a `SortedList` could selectively exploit behaviors that are expected with `list` objects, such as the ability of the `len` function to offer a meaningful measure of the size of the object. See the discussion How do I make len() work with my class?.

In the following, we select only instances of `list` objects as arguments to pass to the `len` function, and these include instances of `SortedList`:

``````class SortedList(list):
def __init__(self, values):
self.values = sorted(values)
def append(self, value):
self.values.append(value)
self.values.sort()
def __repr__(self):
return str(self.values)
def __len__(self):
return len(self.values)

list_of_wannabe_lists = [[1, 2, 3],
SortedList([9, 7, 11]),
144,
SortedList([7, 2])
]

for item in list_of_wannabe_lists:
if isinstance(item, list):
print(len(item))
else:
print("non-list encountered")
``````

Output:

``````3
3
non-list encountered
2
``````

A note of caution is in order here. In the above, we implemented use of the `len` function, but real `list` objects can also be sliced. There are also various `list` methods that users of `SortedList` objects might elect to call. If we are to enable `SortedList` instances to function as bona fide `list` instances, we would need to implement all of that functionality.

1 Like

Wow guys, thank you all for chiming in!!

In the end i think the interpretation of that exercise i went for the self.values = sorted(values) in the constructor.

I was under some impression that i could return the sorted list without declaring it in an object, but like was put earlier, you just get an empty list.

But what a great discussion to see many of the things i tried put here… i thought i was loosing the plot or not getting it.

2 Likes