理解列表推导式与传统循环构建的区别

3

我希望你能帮助我熟练掌握列表的使用,我已经了解到列表推导式并且阅读了大量相关资料,但是有一个问题一直困扰着我。

考虑以下挑战:

def matrix_mult(m1, m2):
    """
      >>> matrix_mult([[1, 2], [3,  4]], [[5, 6], [7, 8]])
      [[19, 22], [43, 50]]
      >>> matrix_mult([[1, 2, 3], [4,  5, 6]], [[7, 8], [9, 1], [2, 3]])
      [[31, 19], [85, 55]]
      >>> matrix_mult([[7, 8], [9, 1], [2, 3]], [[1, 2, 3], [4, 5, 6]])
      [[39, 54, 69], [13, 23, 33], [14, 19, 24]]
    """

我创建了这个解决方案,对我来说它似乎是最合乎逻辑的,并且符合我的以往编程经验,我差不多是边思考边打字...

# 1 using a traditional List buildup method    
res = []
for i in range(len(m1)):
    sub = []
    for j in range(len(m2[0])):
        sub.append(row_times_column( m1, i, m2, j ))
    res.append(sub)
return res

然后我找到了这个解决方案,它使用了“列表推导式”(我将变量重命名以匹配我的变量,以便更好地理解两个解决方案之间的差异:

# 2 using list comprehension
res = [[0] * len(m1) for x in xrange(len(m2[0]))]
for i in range(len(res)):
   for j in range(len(res[i])):
       res[i][j] = row_times_column(m1, i, m2, j)
return res

第二种解决方案是构建一个与预期答案形状相匹配的零基矩阵,但这种方法是否就是所谓的“列表推导”?还是这里有更多的东西?以下是row_times_column()函数的完整定义。
def row_times_column(m1, row, m2, column):
    """
      >>> row_times_column([[1, 2], [3, 4]], 0, [[5, 6], [7, 8]], 0)
      19
      >>> row_times_column([[1, 2], [3, 4]], 0, [[5, 6], [7, 8]], 1)
      22
    """
    i = 0
    for index, value in enumerate(m1[row]):
       i += value * m2[index][column]
    return i

我怀疑有第三种(甚至更多)使用lambda解决这个问题的方法,但我想先请教一下这两种方法的评论。

示例摘自http://openbookproject.net/thinkcs/python/english2e/ch09.html

编辑 现在对列表推导式有了更好的掌握,感谢这里给出的答案。

仍然有人能够解释创建一个空矩阵并将正确答案放入其中的逻辑,而不是创建一个新列表吗?


如果你之前没有创建一个空矩阵,那么使用 res[i][j] = 语法会报错,因为项不存在;所以你必须使用 res.append(),虽然这种语法不如这里优雅。我认为这是唯一的原因。 - littlegreen
5个回答

7

列表推导式是一种简单的根据另一个列表(或其他可迭代项)创建列表的方法。

例如,如果我们有一个列表 a = [1, 2, 5, 7],那么我们可以用两种方式创建一个包含 a 中值加倍的列表 b

没有使用列表推导式

b = []
for e in a:
    b.append(2*e)

使用列表推导式

b = [2*e for e in a]

这不仅仅是那样简单。它只是一种基于列表构建列表的简洁语法。

另请参阅:


3
第一行是列表推导式。其余部分则不是。
 return [[row_times_column(m1, i, m2, j) for j in range(len(res[i]))]
     for i in range(len(res))]

3
下面的代码也使用了列表推导式进行矩阵乘法。
def matrix_mult(m1, m2):
  return [[sum(m1[i][k]*m2[k][j] for k in range(len(m2))) for j in range(len(m2[0]))] for i in range(len(m1))]

谢谢Howard,我就猜到这样的东西一定存在,但是想象不出它会是什么样子!我得把它分解开来... - Cups

1

Python中列表推导的原理在PEP 202中有所解释。

在使用map()和filter()和/或嵌套循环的情况下,列表推导提供了一种更简洁的方法来创建列表。

因此,这个想法背后真的没有什么“特殊的诡计”。正如PEP所说,它只是一个“语法扩展”。

希望对你有帮助。


1

Mark Pilgrim在他的书Dive into Python中对列表推导式的解释做得比我好多了。这本书非常适合Python初学者,并且总体上是一本很好的读物。推荐。

P.S.:Dive into Python 3中也有Python 3的列表推导式。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接