【问题标题】:numbers in a list, find average of surroundings列表中的数字,查找周围环境的平均值
【发布时间】:2012-10-11 14:10:06
【问题描述】:

问题:

给定一个数字列表listA,编写一个程序,生成一个新列表listB,其元素数量与listA相同,使得新列表中的每个元素都是其邻居和自身的平均值在原始列表中。

例如,如果listA = [5, 1, 3, 8, 4]listB = [3.0, 3.0, 4.0, 5.0, 6.0],其中:

(5 + 1)/2 = 3.0 
(5 + 1 + 3)/3 = 3.0 
(1 + 3 + 8)/3 = 4.0 
(3 + 8 + 4)/3 = 5.0 
(8 + 4)/2 = 6.0 

所以我可以得到第一部分和最后一部分,因为它们只处理 2 个数字,但对于中间部分我无法得到它。我的循环是错误的,但我不知道确切。这就是我目前所拥有的。

listA= [5,1,3,8,4]

N=len(listA)
print(listA)

listB=[]
listB.append((listA[0]+listA[1])/2)

y=0
x=1
while x in listA:
    y=((listA[x-1] + list[x] + list[x+1])/3)
    listB.append(y)
y=y+1

listB.append((listA[-1]+listA[-2])/2)

print(listB)

【问题讨论】:

  • 这看起来像家庭作业,所以我问你是否已经涵盖了切片。这是使用列表切片的主要候选对象。
  • 我想我们已经讨论过了,当您在列表中使用 : 时不是吗?
  • 这是正确的,当您在索引列表时括号内有一个冒号时。

标签: python list python-3.x


【解决方案1】:

您可以使用迭代器来做到这一点,而无需通过索引循环:

import itertools

def neighbours(items, fill=None):
    before = itertools.chain([fill], items)
    after = itertools.chain(items, [fill]) #You could use itertools.zip_longest() later instead.
    next(after)
    for a, b, c in zip(before, items, after):
        yield [value for value in (a, b, c) if value is not fill]

这样使用:

>>> items = [5, 1, 3, 8, 4]
>>> [sum(values)/len(values) for values in neighbours(items)]
[3.0, 3.0, 4.0, 5.0, 6.0]

那么这是如何工作的呢?我们为之前和之后的值创建了一些额外的迭代器。我们使用itertools.chain 分别在开头和结尾添加一个额外的值,以便让我们在正确的时间获得正确的值(并且不会用完项目)。然后我们将后面的项目推进一个,将其放在正确的位置,然后循环,返回不是None 的值。这意味着我们可以以非常自然的方式循环。

请注意,这需要一个列表,因为迭代器将被耗尽。如果您需要它在迭代器上懒惰地工作,以下示例使用 itertools.tee() 来完成这项工作:

def neighbours(items, fill=None):
    b, i, a = itertools.tee(items, 3)
    before = itertools.chain([fill], b)
    after = itertools.chain(a, [fill])
    next(a)
    for a, b, c in zip(before, i, after):
        yield [value for value in (a, b, c) if value is not fill]

【讨论】:

  • 我从你那里看到了很多很棒的答案。只想说你太棒了!
【解决方案2】:
list_a = [5, 1, 3, 8, 4]
# Start list_b with the special case first element
list_b = [sum(list_a[:1]) / 2.0]
# Iterate over each remaining index in the list
for i in range(1, len(list_a - 1)):
    # Get the slice of the element and it's neighbors
    neighborhood = list_a[i-1:i+1]
    # Add the average of the element and it's neighbors
    # have to calculate the len of neighborhood to handle
    # last element special case
    list_b.append(sum(neighborhood) / float(len(neighborhood)))

【讨论】:

    【解决方案3】:

    可以使用 arcpy.AverageNearestNeighbor_stats

    否则,如果你喜欢循环:

    import numpy as np
    
    listA= [5,1,3,8,4]
    b = []
    
    for r in xrange(len(listA)):
        if r==0 or r==len(listA):
            b.append(np.mean(listA[r:r+2]))
        else: 
            b.append(np.mean(listA[r-1:r+2]))
    

    【讨论】:

      【解决方案4】:

      看来您的想法是对的。不过,您的代码有点难以理解,请尝试在将来使用更具描述性的变量名称 :) 它使每个人都更容易。

      这是我快速而肮脏的解决方案:

      def calcAverages(listOfNums):
          outputList = []
          for i in range(len(listOfNums)):
              if i == 0:
                  outputList.append((listOfNums[0] + listOfNums[1]) / 2.)
              elif i == len(listOfNums)-1:
                  outputList.append((listOfNums[i] + listOfNums[i-1]) / 2.)
              else:
                  outputList.append((listOfNums[i-1] +
                                  listOfNums[i] + 
                                  listOfNums[i+1]) / 3.)
          return outputList
      
      if __name__ == '__main__':
          listOne =  [5, 1, 3, 8, 4, 7, 20, 12]
          print calcAverages(listOne)
      

      我选择了for 循环而不是while。这并没有太大的区别,但我觉得语法更容易理解。

      for i in range(len(listOfNums)):
      

      我们创建了一个循环,它将遍历输入列表的长度。

      接下来我们处理两个“特殊”情况:列表的开头和结尾。

          if i == 0:
              outputList.append((listOfNums[0] + listOfNums[1]) / 2.)
          elif i == len(listOfNums)-1:
              outputList.append((listOfNums[i] + listOfNums[i-1]) / 2.)
      

      所以,如果我们的索引为 0,我们就在开头,所以我们将当前索引的值 0 和下一个最高的 1 相加,取平均值,并将其附加到我们的输出中列表。

      如果我们的索引等于 out list - 1 的长度(我们使用 -1 因为列表从 0 开始索引,而长度不是。如果没有 -1,我们会得到 IndexOutOfRange 错误。)我们知道我们'在最后一个元素上。因此,我们取该位置的值,将其添加到列表中前一个位置的值中,最后将这些数字的平均值附加到输出列表中。

          else:
              outputList.append((listOfNums[i-1] +
                              listOfNums[i] + 
                              listOfNums[i+1]) / 3.)
      

      最后,对于所有其他情况,我们只需获取当前索引处的值,以及紧接其上方和下方的值,然后将平均结果附加到我们的输出列表中。

      【讨论】:

        【解决方案5】:
        In [31]: lis=[5, 1, 3, 8, 4]
        
        In [32]: new_lis=[lis[:2]]+[lis[i:i+3] for i in range(len(lis)-1)]
        
        In [33]: new_lis
        Out[33]: [[5, 1], [5, 1, 3], [1, 3, 8], [3, 8, 4], [8, 4]]
        
              #now using sum() ans len() on above list and using a list comprehension
        
        In [35]: [sum(x)/float(len(x)) for x in new_lis]
        Out[35]: [3.0, 3.0, 4.0, 5.0, 6.0]
        

        或使用zip():

        In [36]: list1=[lis[:2]] + zip(lis,lis[1:],lis[2:]) + [lis[-2:]]
        
        In [37]: list1
        Out[37]: [[5, 1], (5, 1, 3), (1, 3, 8), (3, 8, 4), [8, 4]]
        
        In [38]: [sum(x)/float(len(x)) for x in list1]
        Out[38]: [3.0, 3.0, 4.0, 5.0, 6.0]
        

        【讨论】:

        • 您还可以添加maplambda 以生成最终列表。虽然这对新程序员来说不是很容易解释。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2012-02-20
        • 1970-01-01
        • 2017-06-11
        • 2018-07-12
        • 1970-01-01
        相关资源
        最近更新 更多