[Tutor] saveLine

Avi Gross avigross at verizon.net
Sun Nov 11 13:11:55 EST 2018


Alan and others have answered the questions posed and what I am asking now
is to look at the function he proposed to keep track of the last five lines.

There is nothing wrong with it but I wonder what alternatives people would
prefer. His code is made for exactly 5 lines to be buffered and is quite
efficient. But what if you wanted N lines buffered, perhaps showing a
smaller number of lines on some warnings or errors and the full N in other
cases?

Here is Alan's code for comparison:

buffer = ['','','','','']

def saveLine(line, buff):
    buff[0] = buff[1]
    buff[1] = buff[2]
    buff[2] = buff[3]
    buff[3] = buff[4]
    buff[4] = line

Again, that works fine. If N was not 5, I would suggest initializing the
buffer might look like this:

buffed = 5
buffer = [''] * buffed

Then instead of changing the list in place, I might change the function to
return the new string created by taking the substring containing all but the
first that is then concatenated with the new entry:

def saveLineN(line, buff):
    buff = buff[1:] + [line]
    return buff

Clearly less efficient but more general. And, yes, the return statement
could be the entire function as in:

def saveLineN(line, buff):
    return  buff[1:] + [line]


Here is a transcript of it running:

>>> buffer
['', '', '', '', '']
>>> saveLineN('a', buffer)
['', '', '', '', 'a']
>>> buffer = saveLineN('a', buffer)
>>> buffer
['', '', '', '', 'a']
>>> buffer = saveLineN('b', buffer)
>>> buffer = saveLineN('c', buffer)
>>> buffer = saveLineN('d', buffer)
>>> buffer = saveLineN('e', buffer)
>>> buffer
['a', 'b', 'c', 'd', 'e']
>>> buffer = saveLineN('6th', buffer)
>>> buffer
['b', 'c', 'd', 'e', '6th']

So perhaps using in-line changes might make sense.

Buff.pop(0) would remove the zeroeth item with the side effect of returning
the first item to be ignored. 

>>> buffer = ['a', 'b', 'c', 'd', 'e']
>>> buffer.pop(0)
'a'
>>> buffer
['b', 'c', 'd', 'e']

And it can be extended in-line:

>>> buffer.append('6th')
>>> buffer
['b', 'c', 'd', 'e', '6th']

Sorry, I mean appended, not extended! LOL!

So to make this compact and less wasteful, I consider using del buffer[0]:

>>> del buffer[0]
>>> buffer
['b', 'c', 'd', 'e']

So here is this version that might be more efficient. It deletes the first
item/line of the buffer then adds a new  nth in-line:

def saveLineN2(line, buff):
    del buff[0]
    buff.append(line)

Here is a transcript of it in use, using N=3 to be different:

>>> buffed = 3
		      
>>> buffer = [''] * buffed
		      
>>> buffer
		      
['', '', '']
>>> saveLineN2('First Line\n', buffer)
		      
>>> buffer
		      
['', '', 'First Line\n']
>>> saveLineN2('Second Line\n', buffer)
		      
>>> saveLineN2('Third Line\n', buffer)
		      
>>> buffer
		      
['First Line\n', 'Second Line\n', 'Third Line\n']
>>> saveLineN2('nth Line\n', buffer)
		      
>>> buffer
		      
['Second Line\n', 'Third Line\n', 'nth Line\n']

I can think of many other ways to do this, arguably some are more weird than
others. There is the obvious one which does all the changes in one line as
in:

buff[0],buff[1],buff[2] = buff[1],buff[2],line

Of course, for 5 you change that a bit. Might even be a tad more efficient.

There is also the odd concept of not scrolling along but dealing with things
at print time. I mean you can have a list with 1:N entries and a variable
that holds an index from 1 to N. You store a new line at buffer[index] each
time then you increment index modulo N. This resets it to 0 periodically. At
print time, you print buffer[index:] + buffer[:index] and you have the same
result.

Does anyone have comments on what methods may be better for some purposes or
additional ways to do this? I mean besides reading all lines into memory and
holding on to them and indexing backwards.

For that matter, you can revisit the question of using a list of lines and
consider a dictionary variant which might work better for larger values of
N. No need to slide a buffer window along, just maintain a modular index and
overwrite the key value as in buffer[index] = line

One more comment, if I may. 

Alan mentions but does not define a printBuffer() function. Using any of the
methods above, you can end up with an error happening early on so the kind
of fixed-length buffer mentioned above contains blank entries (not even a
'\n') so it probably should suppress printing items of zero length or that
are empty. And, in some of the methods shown above, it may be worth starting
with an empty buffer and adding lines up to some N and only then removing
the first entry each time. That would complicate the code a bit but make
printing trivial.







More information about the Tutor mailing list