frans
frans

Reputation: 9808

generate a modified copy of a tuple

I know I can't modify a tuple and I've seen ways to create a tuple from another one concatenating parts of the original manually like here.

But wonder whether there has emerged some pythonic way to 'modify' a tuple by implicitly creating a new one like

>>> source_tuple = ('this', 'is', 'the', 'old', 'tuple')
>>> new_tuple = source_tuple.replace(3, 'new')
>>> new_tuple
('this', 'is', 'the', 'new', 'tuple')

A possible implementation could look like this but I'm looking for a built in solution:

def replace_at(source, index, value):
    if isinstance(source, tuple):
        return source[:index] + (value,) + source[index + 1:]
    elif isinstance(source, list):
        return source[:index] + [value,] + source[index + 1:]
    else:
        explode()

it's not much work to implement such a functionality but like the Enum has demonstrated it's sometimes better to have an implementation everyone uses..

Edit: my goal is not to replace the source tuple. I know I could use lists but even in this case I would make a copy first. So I'm really just looking for a way to create a modified copy.

Upvotes: 6

Views: 6653

Answers (4)

dawg
dawg

Reputation: 104111


You can use a slice on the tuple (which yields a new tuple) and concatenate:

>>> x=3
>>> new_tuple=source_tuple[0:x]+('new',)+source_tuple[x+1:]
>>> new_tuple
('this', 'is', 'the', 'new', 'tuple')

Which you can then support either a list or tuple like so:

>>> def replace_at(source, index, value):
...     return source[0:index]+type(source)((value,))+source[index+1:]
...
>>> replace_at([1,2,3],1,'new')
[1, 'new', 3]
>>> replace_at((1,2,3),1,'new')
(1, 'new', 3)

Or, just do it directly on a list:

>>> source_tuple = ('this', 'is', 'the', 'old', 'tuple')
>>> li=list(source_tuple)
>>> li[3]='new'
>>> new_tuple=tuple(li)
>>> new_tuple
('this', 'is', 'the', 'new', 'tuple')

As stated in the comments -- that is what lists are for...

Upvotes: 6

Moses Koledoye
Moses Koledoye

Reputation: 78564

If you're thinking of swapping values on the fly, then a list is the more appropriate data structure; as we already know tuples are immutable.

On another note, if you're looking for a swap-value logic in a tuple, you can have a look at collections.namedtuple which has a _replace method.

They can be used wherever regular tuples are used

>>> source_tuple = ('this', 'is', 'the', 'old', 'tuple')

>>> Factory = namedtuple('Factory', range(5), rename=True)

>>> source_tuple = Factory(*source_tuple)

>>> source_tuple
Factory(_0='this', _1='is', _2='the', _3='old', _4='tuple')

>>> new_tuple = source_tuple._replace(_3='new')

>>> new_tuple
Factory(_0='this', _1='is', _2='the', _3='new', _4='tuple')

Well that doesn't look too elegant. I still suggest you use a list instead.

Upvotes: 4

ShabashP
ShabashP

Reputation: 578

If you need to create new tuple with replaced element, you may use something like this:

def replace_value_in_tuple(t, ind, value):
    return tuple(
        map(lambda i: value if i == ind else t[i], range(len(t)))
    )

Upvotes: 0

Jan
Jan

Reputation: 43199

You could use some kind of comprehension:

source_tuple = ('this', 'is', 'the', 'old', 'tuple')
new_tuple = tuple((value if x != 3 else 'new'
                   for x, value in enumerate(source_tuple)))
# ('this', 'is', 'the', 'new', 'tuple')

This is rather idotic in this case but gives you an idea of the general concept. Better use a list, though, after all, you can change the values index-based here.

Upvotes: 0

Related Questions