Увеличение переменной или присвоение ей элемента-итератора - PullRequest
0 голосов
/ 13 декабря 2011

Я хочу увеличить переменную и - если выполняется определенное условие - я хочу присвоить ей следующий элемент итератора. В обоих случаях результат должен быть добавлен в список.

Проблема в том, что функция распознает только те значения, которые уже есть в итераторе.

Входными данными является вложенный список.

import datetime as dt

dates_prices = [[dt.datetime(2008, 6, 3, 0, 0), 48.54],
                [dt.datetime(2008, 6, 6, 0, 0), 47.99]]

def fillDates(dates_prices):
    filled = []
    iter_data = iter(dates_prices)
    item = iter_data.next()
    filled.append(item)
    while True:
        item[0] += dt.timedelta(1)
        try:
            if item in dates_prices:
                item = iter_data.next()
            filled.append(item)
        except StopIteration:
            return filled

a = fillDates(dates_prices)
print a

Функция должна проверять, какие даты отсутствуют в исходном вложенном списке. Следует добавить все пропущенные даты вместе с последним известным ценовым показателем, поэтому результат будет следующим:

a =
[[dt.datetime(2008, 6, 3, 0, 0), 48.54], 
[dt.datetime(2008, 6, 4, 0, 0), 48.54], 
[dt.datetime(2008, 6, 5, 0, 0), 48.54], 
[dt.datetime(2008, 6, 6, 0, 0), 47.99]]

Что я пропустил?

EDIT:

Я изменил функцию, с которой она работает сейчас, создав отдельный список дат из вложенного списка «date_prices» и применив предложение Sevenforce.

Однако я до сих пор не знаю, почему мое первое решение не сработало. Я думаю, что-то с присвоением переменной было неправильно. Но я не знаю что.

Это новая функция:

import datetime as dt

dates_prices = [[dt.datetime(2008, 6, 3, 0, 0), 48.54], [dt.datetime(2008, 6, 6, 0, 0), 47.99]]

def fillDates(dates_prices):
    filled = []
    dates = [x[0] for x in dates_prices] #added this list
    iter_data = iter(dates_prices)
    item = iter_data.next()
    filled.append(item[:])

    while item[0] < dates[-1]:
        item[0] += dt.timedelta(1)
        if item[0] in dates: #using the new list here
            item = iter_data.next()
        filled.append(item[:]) #added colon here
    return filled


a = fillDates(dates_prices)
print a

Ответы [ 4 ]

2 голосов
/ 13 декабря 2011

Я подозреваю, что dates_prices - это вложенный список.

Возможно, вы захотите добавить копию из item в filter, а не тот же объект. Для этого измените строку filled.append(item) на filled.append(item[:]). Это предотвратит item[0] += dt.timedelta(1) от изменения уже добавленных значений в заполненном.


Чтобы ответить на ваши изменения:

  • Отсутствует еще один [:]: iter_data = iter(dates_prices[:]) предотвращает изменения самого ввода dates_prices (по item[0] += dt.timedelta(1), кстати, это все еще происходит в вашем обновленном коде). Это привело к if item in dates_prices, всегда оцениваем к True.

  • С указанным выше изменением if item in dates_prices будет всегда False, начиная с [dt.datetime(2008, 6, 6, 0, 0), 48.54] != datetime.datetime(2008, 6, 6, 0, 0), 47.99] и, следовательно, ведет в бесконечный цикл.

Другая рабочая версия (отредактированная):

import datetime as dt
import copy

dates_prices = [[dt.datetime(2008, 6, 3, 0, 0), 48.54],
    [dt.datetime(2008, 6, 6, 0, 0), 47.99]]

def fillDates(dates_prices):
    filled = []
    iter_data = iter(copy.deepcopy(dates_prices))  #to copy the datetime objects
    item = iter_data.next()
    filled.append(item[:])
    dates_idx = 1
    while dates_idx < len(dates_prices):
        item[0] += dt.timedelta(1)
        if item[0] == dates_prices[dates_idx][0]:
            item = iter_data.next()
            dates_idx += 1
        filled.append(item[:])
    return filled

a = fillDates(dates_prices)
print a

Но есть еще возможности для улучшения, например, использование словаря для dates_prices.


@jsbueno: Вы правы. Здесь нужно учиться использовать что-то вроде

new_item = [item[0] + dt.timedelta(1), item[1]]

Я думаю.

1 голос
/ 13 декабря 2011

В вашем первом коде item - это список:
затем, item[0] += dt.timedelta(1) изменяет значение этого списка без изменения его идентичности (= место в памяти, заданное id())

Этот список элемент , являющийся элементом списка даты_цены , и его идентификатор остается прежним, список даты_причины продолжает удерживать тот же объект в то же место в памяти, но значение этого объекта изменяется с [dt.datetime (2008,6,3,0,0), 48,54] на [dt.datetime (2008,6,4,0,0), 48,54 ] в списке даты_цены

Следовательно, тест item in dates_prices выдает True и по этой причине item = iter_data.next() немедленно выполняется => объект, полученный из item[0] += dt.timedelta(1), не записывается в заполнено

Мое решение:

import datetime as dt

dates_prices = [[dt.datetime(2008, 6, 3, 0, 0), 48.54],
                [dt.datetime(2008, 6, 6, 0, 0), 47.99]]

def fillDates(dates_prices, daylta = dt.timedelta(1)):
    # dates_prices must be ordered accorded to dates
    all_dates = [el[0] for el in dates_prices]
    ending_date = all_dates[-1]
    itnext = iter(dates_prices).next

    item = itnext()
    filled = [item]
    dateplus = item[0] + daylta

    while dateplus<=ending_date:
        if dateplus in all_dates:
            item = itnext()
        else:
            item = [dateplus,item[1]]
        filled.append(item)
        dateplus = item[0] + dt.timedelta(1)
    return filled

a = fillDates(dates_prices)

for x in a:
    print x

результат

[datetime.datetime(2008, 6, 3, 0, 0), 48.54]
[datetime.datetime(2008, 6, 4, 0, 0), 48.54]
[datetime.datetime(2008, 6, 5, 0, 0), 48.54]
[datetime.datetime(2008, 6, 6, 0, 0), 47.99]

Мой код должен быть рассмотрен ближе, чтобы увидеть, не приведут ли конкретные случаи к ошибкам

.

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

Лучшее решение (короче):

def fillDates(dates_prices, daylta = dt.timedelta(1)):
    d,p = dates_prices[0]
    filled = []
    for datime,price in dates_prices[1:]:
        while d!=datime:
            filled.append([d,p])
            d += daylta 
        p = price
    filled.append([datime,price])
    return filled

EDIT:

замена d,p = datime,price на p = price

1 голос
/ 13 декабря 2011

Проблема в том, что вы ссылаетесь (не копируете) список, когда выбираете элемент из исходного списка date_prices, а затем вносите изменения в этот список в строке

    item[0] += dt.timedelta(1)

Iзначит - ваш «предмет» здесь используется несколько раз в создаваемом вами списке (и в вашем исходном списке) - это одни и те же данные в памяти.

Чтобы это исправить, сделайте копиюitem, перед применением этого назначения - например, вставьте эту строку перед назначением:

    item = item[:]
    item[0] += dt.timedelta(1)

Это сделает ваш «item» копией всех значений предыдущего элемента, а затем вы примените изменениявместо этого.

1 голос
/ 13 декабря 2011

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

Должно быть понятно, что список является объектом и является изменяемым .

Поэтому при изменении элементаНапример, item = [1, 2] с item [0] = 5 item теперь будет [5, 2].Если вы помещаете элемент в скажем ... другой список несколько раз или, для ясности, в кортеж (которые являются неизменяемыми объектами), ссылки на элементы не изменяются, но содержимое элементов изменяется.

Пример выше:

In [162]: foo = [1, 2]

In [163]: bar = (foo, foo, foo)

In [164]: bar
Out[164]: ([1, 2], [1, 2], [1, 2])

In [165]: foo[0] = 5

In [166]: bar
Out[166]: ([5, 2], [5, 2], [5, 2])

Вы можете быть сбиты с толку, но это действительно поражает.Кортеж не изменился и не может изменить .Кортеж просто содержит ссылку на объект, который мы не меняем, изменяя содержимое элемента.Ниже приведен пример, иллюстрирующий эти моменты.

In [167]: baz = [1, 2, 3]

In [168]: bar[0] = baz
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
/Users/litzomatic/Dev/sqlalchemypy/<ipython-input-168-a23696d7bc75> in <module>()
----> 1 bar[0] = baz

TypeError: 'tuple' object does not support item assignment

In [169]: foo.extend(baz)

In [170]: bar
Out[170]: ([5, 2, 1, 2, 3], [5, 2, 1, 2, 3], [5, 2, 1, 2, 3])

In [171]: baz[0] = 6

In [172]: bar
Out[172]: ([5, 2, 1, 2, 3], [5, 2, 1, 2, 3], [5, 2, 1, 2, 3])

Теперь, что нам делать, если мы не хотим такого поведения?Вам нужно создать несколько объектов , а не только один.В Python со списками для этого есть простой синтаксис.

In [174]: bar = (foo[:], foo[:], foo[:])

In [175]: bar
Out[175]: ([5, 2, 1, 2, 3], [5, 2, 1, 2, 3], [5, 2, 1, 2, 3])

In [176]: foo[0] = 10

In [177]: foo
Out[177]: [10, 2, 1, 2, 3]

In [178]: bar
Out[178]: ([5, 2, 1, 2, 3], [5, 2, 1, 2, 3], [5, 2, 1, 2, 3])

Вы можете подтвердить, что происходит, используя оператор is для сравнения ссылок на объекты.

In [179]: bar[0] is foo
Out[179]: False

In [180]: bar = (foo, foo, foo)

In [181]: bar[0] is foo
Out[181]: True

In [182]: foo[0] = 15

In [183]: bar[0] is foo
Out[183]: True

In [184]: bar
Out[184]: ([15, 2, 1, 2, 3], [15, 2, 1, 2, 3], [15, 2, 1, 2, 3])
...