为什么我不能从一个列表推导式中得到两个列表?

5 投票
4 回答
1078 浏览
提问于 2025-04-16 23:51

我有一个这样的数组:

[(1, u'first_type', u'data_gid_1'), 
 (2, u'first_type', u'data_gid_2'), 
 (3, u'first_type', u'data_gid_3'), 
 (4, u'first_type', u'data_gid_4')]

现在我想把每个内部列表的第一个和最后一个元素提取出来,放到两个单独的列表里。所以如果我这样做:

>>> ids = [dat[0] for dat in all_data]
>>> gds = [dat[2] for dat in all_data]

这样做的效果正是我所期待的。不过,我试着把这两个操作合并成一个,比如这样:

 (ids, gds) = [(dat[0], dat[2]) for dat in all_data]

但是这样做就出错了,出现了一个错误信息:ValueError: too many values to unpack

所以,有人能解释一下为什么会这样吗?我想做的事情到底可不可以呢?

祝好,
博格丹

4 个回答

1

[(dat[0], dat[2]) for dat in all_data] 的意思是你在创建一个包含元组的列表,每个元组是 (dat[0], dat[2])。这并不意味着你有两个列表,一个是 d[0],另一个是 d[2]

你可以简单地使用 zip,但这样会得到元组。如果你想要列表,就需要对结果使用 list

(ids, gds) = map(list,zip(*[(dat[0], dat[2]) for dat in a]))
4

下面的代码也能解决这个问题:

data = [(1, u'first_type', u'data_gid_1'), 
 (2, u'first_type', u'data_gid_2'), 
 (3, u'first_type', u'data_gid_3'), 
 (4, u'first_type', u'data_gid_4')]

ids, gds = ([row[i] for row in data] for i in [0,2])
9

这个代码不工作是因为 [(dat[0], dat[2]) for dat in all_data] 的长度和 all_data 的长度是一样的,而这个长度和元组 (ids, gds) 的长度不一样。

试试这个:

(ids, gds) = zip(*[(dat[0], dat[2]) for dat in all_data])

或者更简短一些:

(ids, gds) = zip(*all_data)[::2]

正如另一个回答中提到的,idsgds 现在会变成元组,如果你需要列表,可以这样做:

(ids, gds) = map(list, zip(*all_data)[::2])



zip(*something) 是 Python 中一个常见的用法。如果你把一个列表的列表看作一个矩阵,也就是:

l = [[1, 2, 3],
     [4, 5, 6]]

那么 zip(*l) 就是把这个矩阵转置:

zip(*l) == [(1, 4),
            (2, 5),
            (3, 6)]

* 的作用是这样的:some_func(*some_list) 会把 some_list 中的元素“拆开”,让函数实际上用这些元素作为参数来调用。所以 zip(*l)zip([1, 2, 3], [4, 5, 6]) 是一样的。这里是 Python 教程中相关的部分。

zip 就像一个 拉链,所以这个名字的由来,它返回一个列表,里面的元素是:给定参数中所有第一个元素组成的元组,接着是所有第二个元素组成的元组,依此类推。

撰写回答