###

Question:

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!

###

Solution:1

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[1]] `

###

Solution:2

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

###

Solution:3

`>>> inp = "hello", "my", "friend" >>> index = 1 >>> inp[:index] + ( str.upper(inp[index]),) + inp[index + 1:] ('hello', 'MY', 'friend') `

Seems simple, the only thing you may need to know is that to make a single element tuple, do (elt,)

###

Solution:4

Maybe some' like this?

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

Note: rather than `(x,i) in zip(t, range(len(t)))`

I should have thought of using the enumerate function : `(i,x) in enumerate(t)`

Making it a bit more general:

Rather than hard-coding the 1, we can place it in a variable.

Also, by using a tuple for that purpose, we can apply the function to elements at multiple indexes.

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

Also, we can "replace" the zip()/enumerate() by map(), in something like

`out = tuple(map(lambda x,i : i == 1 and x.upper() or x, inp, range(len(inp)) ) ) `

Edit: (addressing comment about specifying the function to apply):

Could be something as simple as:

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

Since we're talking about applying *any* function, we should mention the small caveat with the `condition and if_true or if_false`

construct which is not *exactly* a substitute for the if/else ternary operator found in other languages. The limitation is that the function cannot return a value which is equivalent to False (None, 0, 0.0, '' for example). A suggestion to avoid this problem, is, with Python 2.5 and up, to use the true if-else ternary operator, as shown in Dave Kirby's answer (note the `when_true if condition else when_false`

syntax of this operator)

###

Solution:5

I don't understand if you want to apply a certain function to every element in the tuple that passes some test, or if you would like it to apply the function to any element present at a certain index of the tuple. So I have coded both algorithms:

This is the algorithm (coded in Python) that I would use to solve this problem in a functional language like scheme:

This function will identify the element identifiable by `id`

and apply `func`

to it and return a list with that element changed to the output of `func`

. It will do this for every element identifiable as `id`

:

`def doSomethingTo(tup, id): return tuple(doSomethingToHelper(list(tup), id)) def doSomethingToHelper(L, id): if len(L) == 0: return L elif L[0] == id: return [func(L[0])] + doSomethingToHelper(L[1:], id) else: return [L[0]] + doSomethingToHelper(L[1:], id) `

This algorithm will find the element at the index of the tuple and apply `func`

to it, and stick it back into its original index in the tuple

`def doSomethingAt(tup, i): return tuple(doSomethingAtHelper(list(tup), i, 0)) def doSomethingAtHelper(L, index, i): if len(L) == 0: return L elif i == index: return [func(L[0])] + L[1:] else: return [L[0]] + doSomethingAtHelper(L[1:], index, i+1) `

###

Solution:6

i also like the answer that Dave Kirby gave. however, as a public service announcement, i'd like to say that this is not a typical use case for tuples -- these are data structures that originated in Python as a means to move data (parameters, arguments) to and from functions... they were not meant for the programmer to use as general array-like data structures in applications -- this is why lists exist. naturally, if you're needing the read-only/immutable feature of tuples, that is a fair argument, but given the OP question, this should've been done with lists instead -- note how there is extra code to either pull the tuple apart and put the resulting one together and/or the need to temporarily convert to a list and back.

**Note:If u also have question or solution just comment us below or mail us on toontricks1994@gmail.com**

EmoticonEmoticon