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

3 投票
5 回答
3238 浏览
提问于 2025-04-16 20:45

我正在努力理解和更好地使用列表(Lists),我遇到了列表推导(list comprehension),并阅读了很多相关内容,但有一个问题让我很困惑。

给定这个挑战:

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

编辑 现在对列表推导有了更好的理解,感谢这里的回答。

不过,能不能有人解释一下,为什么要创建一个空矩阵来放置正确答案,而不是直接创建一个新列表呢?

5 个回答

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))]
3

第一行是一个列表推导式。后面的部分不是。

 return [[row_times_column(m1, i, m2, j) for j in range(len(res[i]))]
     for i in range(len(res))]
7

列表推导式就是一种根据另一个列表(或者其他可迭代的东西)来创建新列表的方法。

举个例子,如果我们有一个列表 a = [1, 2, 5, 7],那么我们可以用两种方式创建一个新列表 b,这个新列表里的值是 a 中每个数的两倍。

不使用列表推导式

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

使用列表推导式

b = [2*e for e in a]

就这么简单。它只是一个很方便的语法,用来根据已有的列表来构建新列表。

相关链接:

撰写回答