假设我有一个列表:
my_list = [[1,2,3],[4,5,6],[7,8,9]]
如何在不做的情况下更改列表中的每个值?:
for x in range(0, 3): for y in range(0, 3): my_list[x][y] = -my_list[x][y]
我试图通过这样做来简化这一过程
my_list = [[[-a, -b, -c] for [a, b, c] in d] for d in my_list]
但价值保持不变.
另一种选择是使用内置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]]
许多答案都是关于创建列表的更改副本,但问题的字面含义是关于列表的就地修改.
这是我的最佳就地列表更改解决方案的版本:
def alter_elements(lst, func): for i, item in enumerate(lst): if isinstance(item, list): alter_elements(item, func) else: lst[i] = func(item)
测试运行:
>>> 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]]
没有列表副本.没有硬编码的界限.没有副作用的列表理解.
可以为此问题编写更通用的解决方案.以下适用于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)
现在,请求的否定函数可以编码如下:
import functools import operator negate = functools.partial(recursive_map, operator.neg)
因此,对于一些任意嵌套的iterables的 集合x
,我们计算它的否定y
如下:
y = negate(x)
附录:
正如用户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))
现在,
all_lists = functools.partial(recursive_iter_map, list) y = all_lists(negate(x))
实际上会立即否定每个元素并返回完整的列表.
请注意,我们可以将嵌套的iterables集合视为树.每个iterable都是一个子树,而非迭代是叶子.因此,我定义的第一个函数在叶子上工作,第二个函数在非叶子上工作.