Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Apply function to one element of a list in Python

I'm looking for a concise and functional style way to apply a function to one element of a tuple and return the new tuple, in Python.

For example, for the following input:

inp = ("hello", "my", "friend")

I would like to be able to get the following output:

out = ("hello", "MY", "friend")

I came up with two solutions which I'm not satisfied with.

One uses a higher-order function.

def apply_at(arr, func, i):
    return arr[0:i] + [func(arr[i])] + arr[i+1:]

apply_at(inp, lambda x: x.upper(), 1)

One uses list comprehensions (this one assumes the length of the tuple is known).

[(a,b.upper(),c) for a,b,c in [inp]][0]

Is there a better way? Thanks!

like image 629
Mathieu Avatar asked Dec 13 '22 22:12

Mathieu


2 Answers

Here is a version that works on any iterable and returns a generator:

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

You can extend this so that instead of one position you can give it a list of positions:

>>> 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'
like image 166
Dave Kirby Avatar answered Dec 29 '22 18:12

Dave Kirby


I commented in support of your first snippet, but here are a couple other ways for the record:

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

(Won't work in Python 3.x.) And:

[inp[0], inp[1].upper(), inp[2]]
like image 20
Darius Bacon Avatar answered Dec 29 '22 16:12

Darius Bacon