views:

152

answers:

5

my current solution-pointers would be

  • ether via a iterator class which yields the new assembled inner lists
  • or via a iter function which yields the new assembled inner lists

is there another, better way to solve this challenge?

Edit

@Glenn: good objection. I wasn't thinking of that because I experienced lists not ordered in the manner I thought.

@THC4k: thank you for your solution. I learned chain.from_iterable

@Mike DeSimone: Hmm tested your solution but something went wrong maybe I missed something yet,...

@Jamie and Odomontois: Thank you for pointing out to be more detailed

my goal

I am forging a small algorithm which transforms a list of tasks – pairs/tuples: (start,stop) – to a simplified list of task, where the overlapping tasks merged together.

One exeption: my algorithm fails when one event is completely overlapped by another (s1 s2 e2 e1 )

Detailed:

  • I've a list 'taskList' with pairs (lesson learned - tuples :).
  • each tuple consists of 2 datetimeobjects: start and end of a task.
  • important: the chronology of 'taskList' where the order is determined by start because tasks may overlapp
  • 'taskList' consists several days, therefore datetime objects

Example, just string representation of time for readability

taskList = [(9:00,10:00),(9:30,11:00),(11:00,12:30),(13:30,14:00),(14:00,18:00)]

final endresult :

result = [(9:00,12:30), (13:30,18:00)]

now my thought was, when I rearrange the 'taskList' in the manner I questioned

taskListT1 = [(9:00,),(10:00,9:30),(11:00,11:00),(12:30,13:30),(14:00,14:00),(18:00,)]

now I can eliminate those tuples (a,b) where a >= b:

taskListT2 = [(9:00,),(12:30,13:30),(18:00,)]

and transform back:

result = [(9:00,12:30), (13:30,18:00)]
A: 

This works, but it feels like something more Pythonic is out there:

l = [[1,2], [3,4], [5,6], [7,8]]
o = []
last = []
for a, b in l:
    o.append(last+[a])
    last = [b]
o.append(last)

print o

prints

[[1], [2, 3], [4, 5], [6, 7], [8]]

This body also works:

o = [[l[0][0]]]
for i in range(len(l)-1):
    o.append([l[i][1], l[i+1][0]])
o.append([l[-1][1]])
Ned Batchelder
Ahhhhhh! One letter variable names!!!
mattbasta
Yeah, I made sure to use i, l, and 1 all in there also, for maximum readability! (jk)
Ned Batchelder
You didn't use `_`. Perl folks love that one.
Mike DeSimone
A: 
l = [[1,2], [3,4], [5,6], [7,8]]
m = [([] if i==0 else [l[i-1][1]] )+([] if i==len(l) else [l[i][0]]) for i in xrange(len(l)+1)]
Odomontois
I hope this is a joke.
Glenn Maynard
@Glenn Maynard meaningfulness of the answer was adapted to meaningfulness of the question.
Odomontois
A: 

Do you mean:

pairs = [[1,2], [3,4], [5,6], [7,8]]
print pairs, '->',
transformed = ([[pairs[0][0]]]+
               [[a,b] for a,b in zip(
                   (second for first, second in pairs[:-1]),
                   (first for first, second in pairs[1:]))]+
               [[pairs[-1][-1]]]
               )
print transformed
""" Output:
[[1, 2], [3, 4], [5, 6], [7, 8]] -> [[1], [2, 3], [4, 5], [6, 7], [8]]
"""
Tony Veijalainen
A: 

This is a generator that can work with a generator or list input, so you don't have to keep everything in memory:

def shift_pairs(inPairs):
    lastPair = None
    for pair in inPairs:
        if lastPair:
            yield [lastPair[1], pair[0]]
        else:
            yield [pair[0]]
        lastPair = pair
    yield [lastPair[1]]

I must point out that, in Python, lists of short, fixed length are usually done as tuples:

def shift_pairs(inPairs):
    lastPair = None
    for pair in inPairs:
        if lastPair:
            yield (lastPair[1], pair[0])
        else:
            yield (pair[0],)
        lastPair = pair
    yield (lastPair[1],)
Mike DeSimone
A: 

Well, here is the solutions with yield:

# transform forwards
def transform_pairs( lst ):
    it = iter(lst)
    a,last = next(it)
    yield [a]
    for a,b in it:
        yield last, a
        last = b
    yield [last]

Transforming the list back should look very similar, but I'll leave that to the reader.

Here is another slightly more complicated one that can transform in both directions. It yield tuples because lists of fixed length are lame.

from itertools import chain

def transform( iterable, offset):
    it = chain.from_iterable(iterable) # turn it back to one long list.
    if offset:
        yield next(it), # the trailing `,` makes this a tuple.
    for item in it:
        try:
            x = next(it)
        except StopIteration: # there is no 2nd item left
            yield item,
        else:
             yield item, x # yield the pair

print list(transform(transform([[1,2],[3,4],[5,6],[7,8]], True), False))
THC4k