假设我有一个列表:
my_list = [[1,2,3],[4,5,6],[7,8,9]]
Run Code Online (Sandbox Code Playgroud)
如何在不做的情况下更改列表中的每个值?:
for x in range(0, 3):
for y in range(0, 3):
my_list[x][y] = -my_list[x][y]
Run Code Online (Sandbox Code Playgroud)
我试图通过这样做来简化这一过程
my_list = [[[-a, -b, -c] for [a, b, c] in d] for d in my_list]
Run Code Online (Sandbox Code Playgroud)
但价值保持不变.
chr*_*ffe 11
另一种选择是使用内置map函数:
>>> my_list = [[1,2,3],[4,5,6],[7,8,9]]
>>> neg = lambda x: -x
>>> f = lambda x: map(neg, x)
>>> map(f, my_list)
[[-1, -2, -3], [-4, -5, -6], [-7, -8, -9]]
Run Code Online (Sandbox Code Playgroud)
许多答案都是关于创建列表的更改副本,但问题的字面含义是关于列表的就地修改.
这是我的最佳就地列表更改解决方案的版本:
def alter_elements(lst, func):
for i, item in enumerate(lst):
if isinstance(item, list):
alter_elements(item, func)
else:
lst[i] = func(item)
Run Code Online (Sandbox Code Playgroud)
测试运行:
>>> sample = [[1,2,3],[4,5,6],[7,8,9]]
>>> alter_elements(sample, lambda x: -x)
>>> print sample
>>> [[-1, -2, -3], [-4, -5, -6], [-7, -8, -9]]
Run Code Online (Sandbox Code Playgroud)
没有列表副本.没有硬编码的界限.没有副作用的列表理解.
可以为此问题编写更通用的解决方案.以下适用于Python 3.0,无论嵌套级别如何.
我们来定义recursive_map:
import collections
def recursive_map(f, iterable):
for e in iterable:
if isinstance(e, collections.Iterable):
yield recursive_map(f, e)
else:
yield f(e)
Run Code Online (Sandbox Code Playgroud)
现在,请求的否定函数可以编码如下:
import functools
import operator
negate = functools.partial(recursive_map, operator.neg)
Run Code Online (Sandbox Code Playgroud)
因此,对于一些任意嵌套的iterables的 集合x,我们计算它的否定y如下:
y = negate(x)
Run Code Online (Sandbox Code Playgroud)
附录:
正如用户chradcliffe所指出的,上面的negate函数产生了一个生成器,它可能包含其他生成器......等.为了扩展/评估所有这些生成器,我们需要应用于所有这些生成器list().所以我们定义了另一个通用映射函数,这次是一个可以处理迭代本身的函数.
def recursive_iter_map(f, iterable):
def rec(e):
if isinstance(e, collections.Iterable):
return recursive_iter_map(f, e)
else:
return e
return f(map(rec, iterable))
Run Code Online (Sandbox Code Playgroud)
现在,
all_lists = functools.partial(recursive_iter_map, list)
y = all_lists(negate(x))
Run Code Online (Sandbox Code Playgroud)
实际上会立即否定每个元素并返回完整的列表.
请注意,我们可以将嵌套的iterables集合视为树.每个iterable都是一个子树,而非迭代是叶子.因此,我定义的第一个函数在叶子上工作,第二个函数在非叶子上工作.