LINUX.ORG.RU

Склеивание элементов list в python

 


0

4

Есть list вида:

[
{ "begin" :date object1, "end" : date object2 }
....
{ "begin" :date object3, "end" : date object4 }
]

нужно «склеить» эти временные отрезки по условию

if cur.end == next.begin - datetime.timedelta(seconds=1))
    cur.end = next.end
    delete next
Как это сделать ? По идее нужно мутить рекурсию но есть ли проще что нибудь на встроенных итераторах python ?



Последнее исправление: Jopich (всего исправлений: 3)

List с элементами вида имелось ввиду?

Ip0 ★★★★
()

Вижу только один вариант: пройти по списку в цикле и

  1. Найти самый ранний begin.
  2. Построить словарь вида «end» → словарь «begin, end».

Затем склеить очевидным способом.

P.S. Разработчики PyPy3 рекомендуют использовать для структур с ограниченным количеством полей классы, а не словари, поскольку оптимизация проще.

proud_anon ★★★★★
()

datetime.timedelta(seconds=1)

Строго на 1 секунду позже или ± секунду? Если строго, то пробегаешься по списку и делаешь ends = {x[end] + datetime.timedelta(seconds=1): x for x in your_list} плюс used_stuff = set(), потом для каждого элемента тупо проверяешь, есть он в used_stuff, если есть — скипаешь, если нет — ищешь в ends, нашёл — склеиваешь и добавляешь в used_stuff то, с чем склеил, не нашёл — возвращаешь как есть. O(nlogn) вроде как.

x3al ★★★★★
()
Последнее исправление: x3al (всего исправлений: 1)
Ответ на: комментарий от x3al

Если в исходном списке могут быть дубли — used_stuff = set() сломается, впрочем.

x3al ★★★★★
()
Ответ на: комментарий от x3al

только те что подряд. Но их может быть несколько. Т е после n итерации нужно видимо заново по list проходить ?

Jopich
() автор топика
Ответ на: комментарий от Jopich

Тогда примитивно.

def join_by_date(your_list):
    the_iter = iter(your_list)
    prev_record = next(the_iter)
    for record in the_iter:
        if record["begin"] == prev_record["end"] + datetime.timedelta(seconds=1):
            prev_record["end"] = record["end"]
        else:
            yield prev_record
            prev_record = record
    yield prev_record

O(n), проходить ровно 1 раз. Можешь строить список вместо yield либо потом скастовать list(join_by_date(your_list)).

x3al ★★★★★
()
Ответ на: комментарий от proud_anon

P.S. Разработчики PyPy3 рекомендуют использовать для структур с ограниченным количеством полей классы, а не словари, поскольку оптимизация проще.

А как же https://docs.python.org/3/library/collections.html#collections.namedtuple ?

Deleted
()
Ответ на: комментарий от Deleted

Насчёт именованных кортежей разработчики PyPy в той презентации, вроде, ничего не говорили. Однако это же внутри тот же конструктор класса, так что должно работать.

proud_anon ★★★★★
()

Ышо вариант, на глаз:

L = [1,2,4,5,7,8,10]
dt = 1

R = [L[0]]

for i in range(1,len(L)):
    cur = R[-1]
    nxt = L[i]
    
    if cur + dt == nxt:
        R[-1] = nxt
        continue
        
    R.append(nxt)
    
print(R)

#> [2, 5, 8, 10]
anonymous
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.