对变量进行自增或为其赋值迭代器元素



我想增加一个变量,如果满足特定条件,我想将迭代器的下一个元素赋值给它。在这两种情况下,结果都应该添加到列表中。

问题是,函数只识别迭代器中已经存在的值。

输入数据是一个嵌套列表。

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

我错过了什么?

编辑:

我通过从嵌套列表"dates_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

我怀疑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]]
我认为

问题是,当您从原始date_prices列表中获取项目时,您正在引用(不复制)列表-然后您在

行中对该列表进行更改
    item[0] += dt.timedelta(1)

我的意思是-你在这里的"项目"在你正在创建的列表(和你的原始列表)中被使用了几次-它在内存中是相同的数据。

要解决这个问题,在应用这个赋值之前,复制一个项目-例如,在赋值之前插入这一行:

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

这将使你的"item"成为前一个项目的所有值的副本,然后你将更改应用到这个副本。

编辑:

需要明确的是,列表是对象,并且是可变的

所以当你修改一个元素时,例如item = [1,2], item[0] = 5, item将变成[5,2]。如果你把item放在。另一个列表多次或为了清晰起见,一个元组(不可变对象),项引用不会改变,但项的内容会改变。

上面的例子:

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

你可能会感到困惑,但这真的很重要。元组没有改变,而且不能改变。元组只是包含一个对象的引用,我们不会通过改变item的内容来改变它。下面的例子说明了这些要点。

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

在你的第一个代码中,item是一个列表:
然后,执行item[0] += dt.timedelta(1)修改该列表的值,而不改变其标识(=内存中的位置,由id()给出)

列表item作为列表dates_prices的一个元素,它的身份保持不变,列表dates_prices继续在内存的相同位置保存相同的对象,但是该对象的值从[dt.datetime(2008,6,3,0,0), 48.54]变为列表dates_prices

中的[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
编辑:

d,p = datime,price替换为p = price

最新更新