提问人:Conrad.Dean 提问时间:4/15/2011 最后编辑:MERoseConrad.Dean 更新时间:12/5/2015 访问量:38426
就地修改嵌套列表元素的最优雅方式
Most elegant way to modify elements of nested lists in place
问:
我有一个 2D 列表,如下所示:
table = [['donkey', '2', '1', '0'], ['goat', '5', '3', '2']]
我想将最后三个元素更改为整数,但下面的代码感觉非常难看:
for row in table:
for i in range(len(row)-1):
row[i+1] = int(row[i+1])
但我宁愿有看起来像这样的东西:
for row in table:
for col in row[1:]:
col = int(col)
我认为应该有一种方法来编写上面的代码,但是切片创建了一个与原始列表分开的迭代器/新列表,因此引用不会继承。
有没有办法得到一个更 Python 的解决方案?
答:
1赞
Nicholas Mancuso
4/15/2011
#1
使用列表推导式:
table = [row[0] + [int(col) for col in row[1:]] for row in table]
评论
0赞
Conrad.Dean
4/15/2011
+1 我不知道你可以像这样将列表理解链接在一起!我可能不会使用这种嵌套的东西,因为我和很多人一起工作,他们可能会觉得这不可读,但我肯定会在个人项目中牢记这一点。谢谢!
3赞
Wesley
4/15/2011
#2
你的“丑陋”代码可以通过调用两个参数来改进:range
for row in table:
for i in range(1, len(row)):
row[i] = int(row[i])
如果您坚持在不分配新的临时列表的情况下更改原地的项目(通过使用列表推导和/或切片),这可能是您可以做的最好的事情。请参阅 Python 中是否有等同于“map”的就地?map
虽然我不推荐它,但你也可以通过引入你自己的就地映射函数来使这段代码更通用:
def inplacemap(f, items, start=0, end=None):
"""Applies ``f`` to each item in the iterable ``items`` between the range
``start`` and ``end``."""
# If end was not specified, make it the length of the iterable
# We avoid setting end in the parameter list to force it to be evaluated on
# each invocation
if end is None:
end = len(items)
for i in range(start, end):
items[i] = f(items[i])
for row in table:
inplacemap(int, row, 1)
就个人而言,我发现这不那么 Pythonic。最好只有一种明显的方法可以做到这一点,而事实并非如此。
13赞
MAK
4/15/2011
#3
尝试:
>>> for row in table:
... row[1:]=map(int,row[1:])
...
>>> table
[['donkey', 2, 1, 0], ['goat', 5, 3, 2]]
AFAIK,分配给切片会强制就地完成操作,而不是创建一个新的 .list
list
-1赞
Senthil Kumaran
4/15/2011
#4
这完成了您正在寻找的内容。这是一个可读的解决方案。您也可以使用 listcomp 进行类似的选择。
>>> for row in table:
... for i, elem in enumerate(row):
... try:
... int(elem)
... except ValueError:
... pass
... else:
... row[i] = int(elem)
...
20赞
Shekhar
4/15/2011
#5
for row in table:
row[1:] = [int(c) for c in row[1:]]
上面看起来更像蟒蛇吗?
0赞
Keith
4/15/2011
#6
这将起作用:
table = [[row[0]] + [int(v) for v in row[1:]] for row in table]
但是,您可能需要考虑在首次创建列表时进行转换。
8赞
gurney alex
4/15/2011
#7
我非常喜欢 Shekhar 的回答。
一般来说,在编写 Python 代码时,如果你发现自己在写 f,你就做错了:or i in range(len(somelist))
- 如果您有一个列表,请尝试
enumerate
- 尝试,或者如果您有 2 个或更多要并行迭代的列表
zip
itertools.izip
在您的情况下,第一列是不同的,因此您不能优雅地使用枚举:
for row in table:
for i, val in enumerate(row):
if i == 0: continue
row[i] = int(val)
评论