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