python: [[1,2], [3,4], [5,6], [7,8]] превращаются в [[1], [2,3], [4,5], [6,7] ], [8]] и наоборот - PullRequest
3 голосов
/ 16 августа 2010

мои текущие указатели решений будут

  • эфиром через класс итератора, который выдает новые собранные внутренние списки
  • , или через функцию iter, которая выдает новые собранные внутренние списки

есть ли другой, лучший способ решить эту проблему?

Редактировать

@ Гленн: хорошее возражение.Я не думал об этом, потому что у меня были списки, упорядоченные не так, как я думал.

@ THC4k: спасибо за ваше решение.Я узнал chain.from_iterable

@ Mike DeSimone: Хмм, проверил ваше решение, но что-то пошло не так, может быть, я что-то еще упустил, ...

@ Jamie and Odomontois: Спасибо, что указали наболее подробно

моя цель

Я подделываю небольшой алгоритм, который преобразует список задач - пар / кортежей: (начало, остановка) - в упрощенный списокзадача, в которой перекрывающиеся задачи объединены.

Одно исключение: мой алгоритм завершается ошибкой, когда одно событие полностью перекрывается другим (s1 s2 e2 e1)

Подробно:

  • У меня есть список 'taskList' с парами (урок - кортежи :).
  • каждый кортеж состоит из 2 объектов datetime: начало и конец задачи.
  • важно: хронология 'taskList', где порядок определяется при запуске, поскольку задачи могут перекрываться
  • 'taskList' состоит из нескольких дней, поэтому объекты datetime

Пример, только строковое представление времени для читабельности

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

окончательный конечный результат:

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

Теперь моя мысль была, когда я переставил 'taskList' способом, который я задал

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

теперь я могу исключить те кортежи (a, b), где a> = b:

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

и преобразовать обратно:

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

Ответы [ 6 ]

1 голос
/ 02 августа 2011

Переход к варианту «другой, лучший путь» (даже корректное исключение OP):

def compress_task_list(tasks):
    tasks = list(tasks)
    tasks.sort(key=lambda item: item[0]) # make sure list is in order by start time
    result = []
    first_start = tasks[0][0]
    final_stop = tasks[0][1]
    for start, stop in tasks[1:]:
        if start > final_stop:
            result.append((first_start, final_stop))
            first_start = start
            final_stop = stop
        elif stop > final_stop:
            final_stop = stop
    result.append((first_start, final_stop))
    return tuple(result)

if __name__ == '__main__':
    import unittest

    class Test_Compress_Task_List(unittest.TestCase):
        def test_01(self):
            "completely separate"
            initial = ((8.0, 9.5), (10.0, 12.0), (13.0, 15.5), (16.0, 17.0))
            expected = ((8.0, 9.5), (10.0, 12.0), (13.0, 15.5), (16.0, 17.0))
            self.assertEqual(compress_task_list(initial), expected)
        def test_02(self):
            "end equals start"
            initial = ((8.0, 9.5), (9.5, 12.0), (13.0, 15.5), (15.5, 17.0))
            expected = ((8.0, 12.0), (13.0, 17.0))
            self.assertEqual(compress_task_list(initial), expected)
        def test_03(self):
            "end equals start (with more empty times)"
            initial = ((8.0, 8.5), (8.5, 10.0), (10.25, 12.0), (12.5, 13.75), (13.75, 15.0), (15.25, 16.0), (16.0, 17.0))
            expected = ((8.0, 10.0), (10.25, 12.0), (12.5, 15.0), (15.25, 17.0))
            self.assertEqual(compress_task_list(initial), expected)
        def test_04(self):
            "out of order, cross-overs, and tasks completely inside other tasks"
            initial = ((8.0, 8.5), (8.0, 10.0), (10.25, 12.0), (10.0, 11.5), (13.0, 15.5), (14.0, 15.0), (16.0, 17.0))
            expected = ((8.0, 12.0), (13.0, 15.5), (16.0, 17.0))
            self.assertEqual(compress_task_list(initial), expected)

    unittest.main()

Помните, что это Python, и значение читабельности.;)

1 голос
/ 17 августа 2010

Ну, вот решения с выходом:

# 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]

Преобразование списка обратно должно выглядеть очень похоже, но я оставлю это читателю.

Вот еще один немногоболее сложный, который может трансформироваться в обоих направлениях.Это дает кортежи, потому что списки фиксированной длины: 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))
0 голосов
/ 17 августа 2010

Это генератор, который может работать с входом генератора или списка, поэтому вам не нужно хранить все в памяти:

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]]

Я должен отметить, что в Python списки, фиксированная длина обычно выполняется в виде кортежей:

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],)
0 голосов
/ 17 августа 2010

Вы имеете в виду:

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]]
"""
0 голосов
/ 16 августа 2010
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)]
0 голосов
/ 16 августа 2010

Это работает, но кажется, что-то более Pythonic там:

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

печатает

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

Это тело также работает:

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]])
...