在Python中对列表中的一个元素应用函数

5 投票
6 回答
4301 浏览
提问于 2025-04-15 21:09

我想找一种简洁又实用的方法,在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 个回答

2

也许可以这样做?

>>>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)。

7

这里有一个可以在任何可迭代对象上工作的版本,它会返回一个生成器:

>>> 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'
2

我之前支持了你第一个代码片段的评论,不过这里还有其他几种方法供你参考:

(lambda (a,b,c): [a,b.upper(),c])(inp)

(在Python 3.x中不适用。)还有:

[inp[0], inp[1].upper(), inp[2]]

撰写回答