在Python中对列表中的一个元素应用函数
我想找一种简洁又实用的方法,在Python中对元组中的一个元素应用一个函数,并返回新的元组。
比如,对于下面这个输入:
inp = ("hello", "my", "friend")
我希望能得到这样的输出:
out = ("hello", "MY", "friend")
我想出了两个解决方案,但都不太满意。
一个是用高阶函数。
def apply_at(arr, func, i):
return arr[0:i] + [func(arr[i])] + arr[i+1:]
apply_at(inp, lambda x: x.upper(), 1)
另一个是用列表推导式(这个方法假设元组的长度是已知的)。
[(a,b.upper(),c) for a,b,c in [inp]][0]
有没有更好的方法呢?谢谢!
6 个回答
也许可以这样做?
>>>inp = ("hello", "my", "friend")
>>>out = tuple([i == 1 and x.upper() or x for (x,i) in zip(t,range(len(t)))])
>>> out
('hello', 'MY', 'friend')
注意:我本应该用 (i,x) in enumerate(t)
,而不是 (x,i) in zip(t, range(len(t)))
,这样会更好。
让我们把这个变得更通用一些:
与其把数字1写死在代码里,不如把它放到一个变量里。
而且,通过使用元组,我们可以对多个索引的元素应用这个函数。
>>>inp = ("hello", "my", "friend")
>>>ix = (0,2)
>>>out = tuple([i in ix and x.upper() or x for (i, x) in enumerate(t)])
>>> out
('HELLO', 'my', 'FRIEND')
另外,我们可以用 map() 来“替代” zip()/enumerate(),像这样:
out = tuple(map(lambda x,i : i == 1 and x.upper() or x, inp, range(len(inp)) ) )
编辑:(回应关于指定要应用的函数的评论):
可以是非常简单的东西:
>>> f = str.upper # or whatever function taking a single argument
>>> out = tuple(map(lambda x,i : i == 1 and f(x) or x, inp, range(len(inp)) ) )
既然我们在讨论应用 任何 函数,我们就应该提到一个小注意事项,关于 condition and if_true or if_false
这种写法,它并不是其他语言中 if/else 三元运算符的 完全 替代。限制在于,这个函数不能返回一个等同于 False 的值(比如 None、0、0.0、'' 等)。为了避免这个问题,建议在 Python 2.5 及以上版本中使用真正的 if-else 三元运算符,正如 Dave Kirby 的回答中所示(注意这个运算符的语法是 when_true if condition else when_false
)。
这里有一个可以在任何可迭代对象上工作的版本,它会返回一个生成器:
>>> inp = ("hello", "my", "friend")
>>> def apply_nth(fn, n, iterable):
... return (fn(x) if i==n else x for (i,x) in enumerate(iterable))
...
>>> tuple(apply_nth(str.upper, 1, inp))
('hello', 'MY', 'friend')
你可以进一步扩展这个功能,让它不仅能处理一个位置,还能接收一个位置列表:
>>> def apply_at(fn, pos_lst, iterable):
... pos_lst = set(pos_lst)
... return (fn(x) if i in pos_lst else x for (i,x) in enumerate(iterable))
...
>>> ''.join(apply_at(str.upper, [2,4,6,8], "abcdefghijklmno"))
'abCdEfGhIjklmno'
我之前支持了你第一个代码片段的评论,不过这里还有其他几种方法供你参考:
(lambda (a,b,c): [a,b.upper(),c])(inp)
(在Python 3.x中不适用。)还有:
[inp[0], inp[1].upper(), inp[2]]