我想增加一个变量,如果满足特定条件,我想将迭代器的下一个元素赋值给它。在这两种情况下,结果都应该添加到列表中。
问题是,函数只识别迭代器中已经存在的值。
输入数据是一个嵌套列表。
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