【问题标题】:Referencing list entries within a for loop without indexes, possible?在没有索引的 for 循环中引用列表条目,可能吗?
【发布时间】:2011-03-30 18:32:51
【问题描述】:

关于 python for 循环的一个特别感兴趣的问题。工程程序通常需要以前或将来的索引值,例如:

for i in range(0,n):
    value = 0.3*list[i-1] + 0.5*list[i] + 0.2*list[i+1]

等等……

不过我更喜欢简洁的 Python 语法:

for item in list:
    #Do stuff with item in list

或二维点数据列表:

for [x,y] in list:
    #Process x, y data

我喜欢循环遍历列表而不显式使用索引来引用列表中的项目的概念。我想知道是否有一种干净的方法可以在不循环索引(或不单独跟踪索引)的情况下获取上一个或下一个项目?

编辑:

感谢 Andrew Jaffe(以及代理 Mark Byers)和 gnibbler 提供的简单、可扩展的示例。直到现在我还不知道 itertools 或 nwise 模块。 John Machin - 感谢您提供了一个非常复杂的示例,说明不该做什么。您在这个示例中付出了很多努力,显然我提出的有点递归的算法无法生成与输入列表具有相同数量元素的列表,并且如果不使用显式索引会出现问题。像这样的算法通常会出现在信号处理中。

【问题讨论】:

    标签: python loops indexing


    【解决方案1】:

    要访问一个元素和下一个元素,您可以使用itertools documentation 中显示的成对recipe

    def pairwise(iterable):
        "s -> (s0,s1), (s1,s2), (s2, s3), ..."
        a, b = tee(iterable)
        next(b, None)
        return izip(a, b)
    

    这可以调整为允许访问三个相邻的元素,而不仅仅是两个。

    【讨论】:

      【解决方案2】:

      这是一个基于 itertools 成对代码的配方,它进行一般的 n 向分组:

      import itertools
      
      def nwise(iterable, n=2):
          "s->(s_0,s_1, ..., s_n), (s_1,s_2,..., s_n+1), ... "
          ntup = itertools.tee(iterable, n)
          for i, item in enumerate(ntup):
              for ii in range(i):
                  next(item, None)
          return itertools.izip(*ntup)
      

      可以这样使用:

      >>> import nwise
      >>> ll = range(10)
      >>> for tup in nwise.nwise(ll,3): print tup
      ... 
      (0, 1, 2)
      (1, 2, 3)
      (2, 3, 4)
      (3, 4, 5)
      (4, 5, 6)
      (5, 6, 7)
      (6, 7, 8)
      (7, 8, 9)
      

      [感谢 Mark Byers 对这个想法的回答]

      【讨论】:

        【解决方案3】:
        >>> from itertools import islice, izip
        >>> seq = range(10)
        >>> for x,y,z in izip(*(islice(seq,i,None) for i in range(3))):
        ...  print x,y,z
        ... 
        0 1 2
        1 2 3
        2 3 4
        3 4 5
        4 5 6
        5 6 7
        6 7 8
        7 8 9
        

        这可以简单地扩展到超过 3 个项目。

        如果您需要它与任何可迭代对象一起使用,Andrew 的答案是合适的,或者您可以这样做

        >>> from itertools import izip, islice, tee
        >>> seq=(x for x in range(10))
        >>> for x,y,z in izip(*(islice(j,i,None) for i,j in enumerate(tee(seq,3)))):
        ...  print x,y,z
        ... 
        0 1 2
        1 2 3
        2 3 4
        3 4 5
        4 5 6
        5 6 7
        6 7 8
        7 8 9
        

        【讨论】:

          【解决方案4】:

          如果您想使用 zip,以下是如何不使用它(填充,不必要)以及如何不检查它(填充 x 2.5),并纠正这些缺陷。

          vector = [2**i for i in range(1,6)]
          print "vector", vector
          value = []
          for i in range(1,len(vector)-1):
              value.append(0.3*vector[i-1] + 0.5*vector[i] + 0.2*vector[i+1])
          
          print "value", len(value), value
          value2=[0.3*before + 0.5* this + 0.2 * after
                    for before,this,after in zip(vector,vector[1:]+[0], vector[2:]+[0,0])
                    ]
          # above +[0] and +[0,0] needlessly extend the answer by two items
          print "value2", len(value2), value2          
          print "bad check bad values", not any([x-y for x,y in zip(value,value2) if x-y > 1e-7])
          # the bad check doesn't check for length 
          # the bad check doesn't use abs(actual - expected)
          # the bad check has a unnecessary if test in it
          # the bad check uses a list comprehension when a generator would do
          print "good check bad values", (
              len(value2) == len(value)
              and
              not any(abs(x-y) > 1e-7 for x,y in zip(value,value2))
              )
          value2=[0.3*before + 0.5* this + 0.2 * after
                    for before,this,after in zip(vector,vector[1:], vector[2:])
                    ]    
          print "fixed value2", len(value2), value2  
          print "good check good values", (
              len(value2) == len(value)
              and
              not any(abs(x-y) > 1e-7 for x,y in zip(value,value2))
              )
          

          【讨论】:

          • 如果向量应该改变长度并且计算仅用于具有两个邻居的那些值,则此解决方案是正确的。示例中的乘数似乎总和为 1.0,并且 0 并不是向量第一个和最后一个数字的真正邻居值。此外,在第一个值的情况下,示例的环绕以作为邻居持续存在是有问题的,但是
          猜你喜欢
          • 2014-09-15
          • 1970-01-01
          • 2020-12-11
          • 2012-01-02
          • 2021-07-16
          • 1970-01-01
          • 2020-07-30
          • 2017-09-07
          • 1970-01-01
          相关资源
          最近更新 更多