alwayssortedlist (was Re: On PEP 322 (ireverse))
Alex Martelli
aleax at aleax.it
Wed Oct 29 15:12:23 EST 2003
More information about the Python-list mailing list
Wed Oct 29 15:12:23 EST 2003
- Previous message (by thread): On PEP 322 (ireverse)
- Next message (by thread): alwayssortedlist (was Re: On PEP 322 (ireverse))
- Messages sorted by: [ date ] [ thread ] [ subject ] [ author ]
Roy Smith wrote: > "Terry Reedy" <tjreedy at udel.edu> wrote: >> As I suggested elsewhere, make iter() the type object for iterator. >> Then iter.reversed is closely parallel to list.sorted. > > I've got a question about list.sorted. I assume it's just a list that's > initialized to have its elements sorted when it's created? We're not > talking about some new magic container type which keeps its elements > sorted all the time? > > In other words, I'm assuming that > > l = list.sorted ((1, 2, 5, 3)) > l.append (4) > print l > > will print [1, 2, 3, 5, 4], right? Perfectly right. If you DO want a listoid container that keeps its elements sorted, that's not hard to make for yourself. There are basically two obvious implementation strategies: -- ensure the underlying list is re-sorted at each insertion, append &c, and/or -- let the underlying list grow as it will on insertion &c, but make sure it's sorted at any method that accesses it (you can use a flag -- 'have there being any append/insert/... since the last sort?' -- to re-sort only when needed). I'll choose the first for general use because: -- accesses are much more frequent than modifications, -- list.sort is VERY fast when a list is "nearly sorted" -- the second approach would require sorting also on many kind of changes (e.g. __setitem__ -- to ensure the items being replaced ARE those the user expects...) &c. So, we clearly start with: class alwayssortedlist(list): def __init__(self, *args): list.__init__(self, *args) self.sort() We need to ensure sorting at creation. We _might_ make the sort method in this class a noop and call list.sort(self) instead, but, naah -- list.sort is SO fast when called on an already sorted list that it ain't even funny, so, choose simplicity. Onwards to simple mods: def append(self, *args): list.append(self, *args) self.sort() def __setitem__(self, *args): list.__setitem__(self, *args) self.sort() ...starting to see a pattern, by any chance...?-) Yep, ALL list mutators we _need_ to override are exactly like this! (We MAY override e.g. index and remove to take advantage of the sortedness, but, that's optional...:-). extend and insert too (now, reverse IS an interesting issue...!-), and __iadd__ and __imul__ (methods creating new lists, such as __add__, __mul__ and __rmul__, are slightly different). Oh, __setslice__, too. Well, doing it in longhand is fine, of course, but why not have a bit more fun with (not showing the __add__ &c): class solist(list): pass def solist_method(methname): list_method = getattr(list, methname) def method(self, *args): list_method(self, *args) self.sort() setattr(solist, methname, method) for n in 'init setitem iadd imul'.split: solist_method('__%s__' % n) for n in 'append extend insert'.split: solist_method('%s' % n) Not much shorter than the boilerplate/longhand, and not perfect (we should make a new function object to give it the right func_name -- as is, all the methods' names will be "method" in tracebacks &c...:-), but sorta fun. Testing & completion left as an exercise to the student... Alex
- Previous message (by thread): On PEP 322 (ireverse)
- Next message (by thread): alwayssortedlist (was Re: On PEP 322 (ireverse))
- Messages sorted by: [ date ] [ thread ] [ subject ] [ author ]
More information about the Python-list mailing list