【问题标题】:Incrementing a variable or assigning an iterator-element to it递增变量或为其分配迭代器元素
【发布时间】:2011-12-13 01:38:20
【问题描述】:

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

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

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

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

【问题讨论】:

  • 您能否提供一个带有预期输出的示例输入?
  • 输入是一个嵌套列表。我添加了示例输入并使我的代码可执行。很抱歉一开始没有这样做。
  • 预期的输出是什么?
  • 我放弃了“try-except”子句,因为它不再给我一个了

标签: python iterator variable-assignment


【解决方案1】:

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

我认为。

【讨论】:

  • 是的输入是一个嵌套列表。但是我将您的更改应用于我的示例,它仍然只返回输入数据中的两个值。
  • 你发现了问题,但没有在适当的地方修复它——破坏程序的是内存中相同数据的分配——
【解决方案2】:

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

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

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

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

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

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

【讨论】:

    【解决方案3】:

    编辑:

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

    因此,当您修改元素时,例如 item = [1, 2] 和 item[0] = 5 item 现在将是 [5, 2]。如果您将 item 放入 say... 另一个列表多次或为清楚起见使用元组(它们是 不可变 对象),则 item 引用不会改变,但 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”在“dates_prices”中附加“item”到“filled”。 'code'if item in dates_prices'code' 只是“item”被“iter_data”的下一个元素更新的条件。不是吗?!
    • 是的,你是对的,我猜我看错了! :( 提供的输入/输出很明显问题的根源。其他人已经提到了问题的根源,但我会在上面重申,因为这是很重要的一点。
    【解决方案4】:

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

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

    因此,测试 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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-08-20
      • 1970-01-01
      • 1970-01-01
      • 2018-11-09
      • 2011-04-16
      • 2017-07-24
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多