递增变量或为其分配迭代器元素

时间:2011-12-13 01:38:20

标签: python iterator variable-assignment

我想增加一个变量,并且 - 如果满足特定条件 - 我想为它分配迭代器的下一个元素。在这两种情况下,结果都应附加到列表中。

问题是,该函数只识别迭代器中已有的值。

输入数据是嵌套列表。

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

4 个答案:

答案 0 :(得分:2)

我怀疑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 :(得分:1)

编辑:

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

因此,当您修改元素时,例如item = [1,2],项目[0] = 5项目现在将为[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])

你可能会感到困惑,但这确实让人感到困惑。 元组未更改无法更改。元组只包含对象的引用,我们不会通过更改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])

答案 2 :(得分:1)

问题是,当您从原始date_prices列表中提取项目时,您正在引用(而不是复制)列表 - 然后您在该行中对该列表进行了更改

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

我的意思是 - 你的“项目”在你正在创建的列表中(以及在你的原始列表中)被多次使用 - 它与内存中的数据相同。

要解决此问题,请在应用此分配之前复制该项目 - 例如,在分配之前插入此行:

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

这将使您的“项目”成为上一项的所有值的副本,然后您将更改应用于此副本。

答案 3 :(得分:1)

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

此列表是列表 dates_prices 的元素,其标识保持不变,列表 dates_prices 继续保持相同对象位于内存中的相同位置,但此对象的值从[dt.datetime(2008,6,3,0,0),48.54]更改为[dt.datetime(2008,6,4,0,0)列表 dates_prices

中的,)48.54]

因此,测试item in dates_prices生成 True ,因此item = iter_data.next()立即执行=&gt;由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