Inserting while itterating

T

Thomas Guettler

Hi,

Simple excerise:

You have a sorted list of integers:
l=[1, 2, 4, 7, 8, 12]

and you should fill all gaps:

result == [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]

How would you code this?

Constrain: The original list should be changed,
don't create a copy.

thomas
 
M

Mike C. Fletcher

Thomas said:
Hi,

Simple excerise:

You have a sorted list of integers:
l=[1, 2, 4, 7, 8, 12]

and you should fill all gaps:

result == [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]
Well, here's the simplest one...
if l:
l[:] = range(l[0],l[-1])

but what you're probably looking for is (untested):

for x in range( len(l)-2, -1, -1 ):
if l[x+1] != l[x]+1:
l[x+1:x+1] = range(l[x]+1,l[x+1])

Enjoy,
Mike

_______________________________________
Mike C. Fletcher
Designer, VR Plumber, Coder
http://members.rogers.com/mcfletch/
 
F

Francis Avila

Thomas Guettler wrote in message ...
Hi,

Simple excerise:

You have a sorted list of integers:
l=[1, 2, 4, 7, 8, 12]

and you should fill all gaps:

result == [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]

How would you code this?

Constrain: The original list should be changed,
don't create a copy.

thomas
This a homework problem?
L = [1, 2, 4, 7, 8, 12]
result = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]
L.extend([i for i in range(L[0], L[-1]) if i not in L])
L.sort()
L == result
True
 
S

Samuel Walters

| Thomas Guettler said |
Hi,

Simple excerise:

You have a sorted list of integers:
l=[1, 2, 4, 7, 8, 12]

and you should fill all gaps:

result == [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]

How would you code this?

Constrain: The original list should be changed, don't create a copy.

thomas

The word "exercise" raises my suspicions that this is a homework problem.
You know you only cheat yourself when you ask others to do your homework.

#simple, but only works for ints
l = [1, 2, 4, 7, 8, 12]
l = range(l[0],l[-1]+1)
print l


#naive, but broader
#only use when sorting is cheap.
l = [1, 2, 4, 7, 8, 12]
#iterate through each possible item.
for x in range(l[0],l[-1]+1):
if x not in l:
l.append(x)
l.sort()
print l


#missing-merge: more general pattern
#useful for strange, hard to sort data:
#where sorting is expensive,
#but comparison is cheap.
l = [1, 2, 4, 7, 8, 12]
missing = []
#iterate through each possible item
for x in range(l[0], l[-1]+1):
#build a list of each missing item.
if x not in l:
missing.append(x)
#merge the two lists
for x in range(0, len(l) + len(missing) - 1):
if l[x] > missing[0]:
l = l[:x] + missing[0:1] + l[x:]
missing.pop(0)
print l

Sam Walters.
 
A

anton muhin

Thomas said:
Hi,

Simple excerise:

You have a sorted list of integers:
l=[1, 2, 4, 7, 8, 12]

and you should fill all gaps:

result == [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]

How would you code this?

Constrain: The original list should be changed,
don't create a copy.

thomas

1:

previous = l[0]
current = 1

while current < len(l):
for e in range(previous + 1, l[current]):
l.insert(current, e)
current += 1
previous = l[current]
current += 1


2:

first, last = l[0], l[-1]
for _ in range(len(l)): l.pop()
l.extend(range(first, last + 1))

:)

hth,
anton.
 
T

Thomas Guettler

Am Wed, 14 Jan 2004 09:43:01 +0100 schrieb Thomas Guettler:
Hi,

Simple excerise:

You have a sorted list of integers:
l=[1, 2, 4, 7, 8, 12]

and you should fill all gaps:

result == [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]

How would you code this?

Constrain: The original list should be changed,
don't create a copy.

No, this is not a homework exerice,
I was just interested if you have better solutions.
Thank you for your solutions.
Mine looks like this:

l=[1, 2, 4, 7, 8, 12]

i=-1
while 1:
i+=1
this=l
if i+1==len(l):
# End of list
break
next=l[i+1]
assert(this<next)
for add in range(this+1, next):
i+=1
l.insert(i, add)
print l
 
M

Mark McEahern

Hi,

Simple excerise:

You have a sorted list of integers:
l=[1, 2, 4, 7, 8, 12]

and you should fill all gaps:

result == [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]

How would you code this?

Constrain: The original list should be changed,
don't create a copy.

In the spirt of unit testing...

#!/usr/bin/env python

import unittest

def fillGaps(seq):
expectedLength = seq[-1] - seq[0] + 1
i = 1
while i < expectedLength:
if seq - seq[i-1] > 1:
seq.insert(i, seq[i-1] + 1)
i += 1

class test(unittest.TestCase):

def test(self):
l = [1, 2, 4, 7, 8, 12]
fillGaps(l)
self.assertEquals(l, range(1, 13))

unittest.main()
 
S

Skip Montanaro

Mark> In the spirt of unit testing...

Mark> #!/usr/bin/env python
...

Here's a version which is much faster if you have large gaps and appears to
be only marginally slower if you have small gaps.

Skip

#!/usr/bin/env python

#!/usr/bin/env python

def fillGaps1(seq):
expectedLength = seq[-1] - seq[0] + 1
i = 1
while i < expectedLength:
if seq - seq[i-1] > 1:
seq.insert(i, seq[i-1] + 1)
i += 1

def fillGaps(seq):
expectedLength = seq[-1] - seq[0] + 1
i = 1
while i < expectedLength:
if seq - seq[i-1] > 1:
gap = seq[i-1] - seq
fill = range(seq[i-1]+1, seq)
seq[i:i] = fill
i += len(fill)
i += 1

if __name__ == "__main__":
import timeit

print "timing with one large gap:"
t = timeit.Timer(setup='from fillgaps import fillGaps1 as fillGaps',
stmt='fillGaps([1, 5000])')
print "old fillgaps:", t.timeit(number=100)
t = timeit.Timer(setup='from fillgaps import fillGaps',
stmt='fillGaps([1, 5000])')
print "new fillgaps:", t.timeit(number=100)

print "timing with many small gaps:"
t = timeit.Timer(setup='from fillgaps import fillGaps1 as fillGaps;l=range(1,5001,2)',
stmt='fillGaps(l)')
print "old fillgaps:", t.timeit(number=100)
t = timeit.Timer(setup='from fillgaps import fillGaps;l=range(1,5001,2)',
stmt='fillGaps(l)')
print "new fillgaps:", t.timeit(number=100)

import unittest
class test(unittest.TestCase):
def test(self):
for fg in (fillGaps1, fillGaps):
l = [1, 2, 4, 7, 8, 12]
fg(l)
self.assertEquals(l, range(1, 13))

l = [1, 5000]
fg(l)
self.assertEquals(l, range(1, 5001))

unittest.main()
 
P

Peter Otten

Skip said:
Mark> In the spirt of unit testing...

Mark> #!/usr/bin/env python
...

Here's a version which is much faster if you have large gaps and appears
to be only marginally slower if you have small gaps.

Skip

#!/usr/bin/env python

#!/usr/bin/env python

def fillGaps1(seq):
if len(seq) == seq[-1]:
raise Exception("nothing to do")
expectedLength = seq[-1] - seq[0] + 1
i = 1
while i < expectedLength:
if seq - seq[i-1] > 1:
seq.insert(i, seq[i-1] + 1)
i += 1

def fillGaps(seq):
expectedLength = seq[-1] - seq[0] + 1
i = 1
while i < expectedLength:
if seq - seq[i-1] > 1:
gap = seq[i-1] - seq
fill = range(seq[i-1]+1, seq)
seq[i:i] = fill
i += len(fill)
i += 1

if __name__ == "__main__":
import timeit

print "timing with one large gap:"
t = timeit.Timer(setup='from fillgaps import fillGaps1 as fillGaps',
stmt='fillGaps([1, 5000])')
print "old fillgaps:", t.timeit(number=100)
t = timeit.Timer(setup='from fillgaps import fillGaps',
stmt='fillGaps([1, 5000])')
print "new fillgaps:", t.timeit(number=100)

print "timing with many small gaps:"
t = timeit.Timer(setup='from fillgaps import fillGaps1 as
fillGaps;l=range(1,5001,2)',
stmt='fillGaps(l)')


I think the list should be initialized in the statement instead of the
setup. Otherwise subsequent passes will measure for range(1, 5000).
print "old fillgaps:", t.timeit(number=100)
t = timeit.Timer(setup='from fillgaps import
fillGaps;l=range(1,5001,2)',
stmt='fillGaps(l)')
print "new fillgaps:", t.timeit(number=100)

import unittest
class test(unittest.TestCase):
def test(self):
for fg in (fillGaps1, fillGaps):
l = [1, 2, 4, 7, 8, 12]
fg(l)
self.assertEquals(l, range(1, 13))

l = [1, 5000]
fg(l)
self.assertEquals(l, range(1, 5001))

unittest.main()

Here's another fillgap version:

def fillGapsPeter(seq):
# inspired by anton muhin
lo = seq[0]
hi = seq[-1]
seq[1:1] = range(lo+1, hi+1)
while len(seq) > hi:
i = seq.pop()
seq[i-lo] = i

def fillGapsMark(seq):
expectedLength = seq[-1] - seq[0] + 1
i = 1
while i < expectedLength:
if seq - seq[i-1] > 1:
seq.insert(i, seq[i-1] + 1)
i += 1

def fillGapsSkip(seq):
expectedLength = seq[-1] - seq[0] + 1
i = 1
while i < expectedLength:
if seq - seq[i-1] > 1:
gap = seq[i-1] - seq
fill = range(seq[i-1]+1, seq)
seq[i:i] = fill
i += len(fill)
i += 1

if __name__ == "__main__":
import timeit, fillgaps, sys
fnames = [fname for fname in dir(fillgaps) if callable(getattr(fillgaps,
fname))]
fnames.sort()
for header, lst in [
("original test case", [1, 2, 4, 7, 8, 12]),
("timing with one large gap:", [1, 5000]),
("timing with many small gaps:", range(1, 5001, 2))]:
print header
for fn in fnames:
t = timeit.Timer(setup='from fillgaps import %s as fillGaps' %
fn,
stmt='fillGaps(%s)' % (lst,))
print "\t%s:" % fn, t.timeit(number=100)
print
import unittest
class test(unittest.TestCase):
def test_all(self):
for fg in [getattr(fillgaps, fn) for fn in fnames]:
l = [1, 2, 4, 7, 8, 12]
fg(l)
self.assertEquals(l, range(1, 13))

l = [1, 5000]
fg(l)
self.assertEquals(l, range(1, 5001))
def test_mine(self):
""" Hard to prove I'm not cheating,
hope I got it right...
"""
class myint(int):
def __repr__(self):
return "my" + int.__repr__(self)

original = map(myint, [1, 2, 4, 7, 8, 12])
l = list(original)
fillGapsPeter(l)
self.assertEquals(l, range(1, 13))
for i in original:
self.assert_(i is l[i-1])
self.assert_(repr(i).startswith("my"))
unittest.main()

My findings:

original test case
fillGapsMark: 0.00151419639587
fillGapsPeter: 0.00127387046814
fillGapsSkip: 0.00162696838379

timing with one large gap:
fillGapsMark: 0.872708797455
fillGapsPeter: 0.0312719345093
fillGapsSkip: 0.0336079597473

timing with many small gaps:
fillGapsMark: 0.973310947418
fillGapsPeter: 0.412738800049
fillGapsSkip: 1.47315406799


Peter
 
P

Peter Abel

Thomas Guettler said:
Hi,

Simple excerise:

You have a sorted list of integers:
l=[1, 2, 4, 7, 8, 12]

and you should fill all gaps:

result == [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]

How would you code this?

Constrain: The original list should be changed,
don't create a copy.

thomas
l = [1, 2, 4, 7, 8, 12]
id(l) 27295112
for i in range(len(l)-1,0,-1):
.... for j in range(l-l[i-1]-1):
.... l.insert(i,l-1)
....
id(l) 27295112
l [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]

Tested, but no idea about timing.

Regards
Peter
 
J

Jeremy Bowers

Hi,

Simple excerise:

You have a sorted list of integers:
l=[1, 2, 4, 7, 8, 12]

and you should fill all gaps:

result == [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]

How would you code this?

Constrain: The original list should be changed,
don't create a copy.

thomas

l[:] = [x for x in range(l[0], l[-1] + 1)]

If you care about timing, you'll want to compare against Peter Abel's
solution; I would not guarantee which is faster. All I can tell you is
which makes more sense to me when I read it.

Actually, maximal readability is

l[:] = [x for x in range(min(l), max(l) + 1)]

but that will *certainly* be less efficient if you know the list is sorted
then my first post.
 
P

Paul Rubin

Jeremy Bowers said:
Actually, maximal readability is

l[:] = [x for x in range(min(l), max(l) + 1)]

but that will *certainly* be less efficient if you know the list is sorted
then my first post.

Um, why the list comprehension? Something wrong with

l[:] = range(min(l), max(l) + 1)

?
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
474,175
Messages
2,570,946
Members
47,497
Latest member
PilarLumpk

Latest Threads

Top