How to change values in a tuple?

Question:

I have a tuple called values which contains the following:

('275', '54000', '0.0', '5000.0', '0.0')

I want to change the first value (i.e., 275) in this tuple but I understand that tuples are immutable so values[0] = 200 will not work. How can I achieve this?

Asked By: Dawood

||

Answers:

It’s possible via:

t = ('275', '54000', '0.0', '5000.0', '0.0')
lst = list(t)
lst[0] = '300'
t = tuple(lst)

But if you’re going to need to change things, you probably are better off keeping it as a list

Answered By: Jon Clements

You can’t. If you want to change it, you need to use a list instead of a tuple.

Note that you could instead make a new tuple that has the new value as its first element.

Answered By: BrenBarn

based on Jon‘s Idea and dear Trufa

def modifyTuple(tup, oldval, newval):
    lst=list(tup)
    for i in range(tup.count(oldval)):
        index = lst.index(oldval)
        lst[index]=newval

    return tuple(lst)

print modTupByIndex((1, 1, 3), 1, "a")

it changes all of your old values occurrences

Answered By: Pooya

EDIT: This doesn’t work on tuples with duplicate entries yet!!

Based on Pooya’s idea:

If you are planning on doing this often (which you shouldn’t since tuples are inmutable for a reason) you should do something like this:

def modTupByIndex(tup, index, ins):
    return tuple(tup[0:index]) + (ins,) + tuple(tup[index+1:])

print modTupByIndex((1,2,3),2,"a")

Or based on Jon’s idea:

def modTupByIndex(tup, index, ins):
    lst = list(tup)
    lst[index] = ins
    return tuple(lst)

print modTupByIndex((1,2,3),1,"a")
Answered By: Trufa

Well, as Trufa has already shown, there are basically two ways of replacing a tuple’s element at a given index. Either convert the tuple to a list, replace the element and convert back, or construct a new tuple by concatenation.

In [1]: def replace_at_index1(tup, ix, val):
   ...:     lst = list(tup)
   ...:     lst[ix] = val
   ...:     return tuple(lst)
   ...:

In [2]: def replace_at_index2(tup, ix, val):
   ...:     return tup[:ix] + (val,) + tup[ix+1:]
   ...:

So, which method is better, that is, faster?

It turns out that for short tuples (on Python 3.3), concatenation is actually faster!

In [3]: d = tuple(range(10))

In [4]: %timeit replace_at_index1(d, 5, 99)
1000000 loops, best of 3: 872 ns per loop

In [5]: %timeit replace_at_index2(d, 5, 99)
1000000 loops, best of 3: 642 ns per loop

Yet if we look at longer tuples, list conversion is the way to go:

In [6]: k = tuple(range(1000))

In [7]: %timeit replace_at_index1(k, 500, 99)
100000 loops, best of 3: 9.08 µs per loop

In [8]: %timeit replace_at_index2(k, 500, 99)
100000 loops, best of 3: 10.1 µs per loop

For very long tuples, list conversion is substantially better!

In [9]: m = tuple(range(1000000))

In [10]: %timeit replace_at_index1(m, 500000, 99)
10 loops, best of 3: 26.6 ms per loop

In [11]: %timeit replace_at_index2(m, 500000, 99)
10 loops, best of 3: 35.9 ms per loop

Also, performance of the concatenation method depends on the index at which we replace the element. For the list method, the index is irrelevant.

In [12]: %timeit replace_at_index1(m, 900000, 99)
10 loops, best of 3: 26.6 ms per loop

In [13]: %timeit replace_at_index2(m, 900000, 99)
10 loops, best of 3: 49.2 ms per loop

So: If your tuple is short, slice and concatenate.
If it’s long, do the list conversion!

Answered By: sjakobi

Depending on your problem slicing can be a really neat solution:

>>> b = (1, 2, 3, 4, 5)
>>> b[:2] + (8,9) + b[3:]
(1, 2, 8, 9, 4, 5)
>>> b[:2] + (8,) + b[3:]
(1, 2, 8, 4, 5)

This allows you to add multiple elements or also to replace a few elements (especially if they are “neighbours”. In the above case casting to a list is probably more appropriate and readable (even though the slicing notation is much shorter).

Answered By: Dave Halter

i did this:

list = [1,2,3,4,5]
tuple = (list)

and to change, just do

list[0]=6

and u can change a tuple 😀

here is it copied exactly from IDLE

>>> list=[1,2,3,4,5,6,7,8,9]

>>> tuple=(list)

>>> print(tuple)

[1, 2, 3, 4, 5, 6, 7, 8, 9]

>>> list[0]=6

>>> print(tuple)

[6, 2, 3, 4, 5, 6, 7, 8, 9]
Answered By: MC_Creep3r

I’ve found the best way to edit tuples is to recreate the tuple using the previous version as the base.

Here’s an example I used for making a lighter version of a colour (I had it open already at the time):

colour = tuple([c+50 for c in colour])

What it does, is it goes through the tuple ‘colour’ and reads each item, does something to it, and finally adds it to the new tuple.

So what you’d want would be something like:

values = ('275', '54000', '0.0', '5000.0', '0.0')

values  = (tuple(for i in values: if i = 0: i = 200 else i = values[i])

That specific one doesn’t work, but the concept is what you need.

tuple = (0, 1, 2)

tuple = iterate through tuple, alter each item as needed

that’s the concept.

Answered By: Aedus

As Hunter McMillen mentioned, tuples are immutable, you need to create a new tuple in order to achieve this. For instance:

>>> tpl = ('275', '54000', '0.0', '5000.0', '0.0')
>>> change_value = 200
>>> tpl = (change_value,) + tpl[1:]
>>> tpl
(200, '54000', '0.0', '5000.0', '0.0')
Answered By: SuperNova

Not that this is superior, but if anyone is curious it can be done on one line with:

tuple = tuple([200 if i == 0 else _ for i, _ in enumerate(tuple)])
Answered By: bphi

I believe this technically answers the question, but don’t do this at home. At the moment, all answers involve creating a new tuple, but you can use ctypes to modify a tuple in-memory. Relying on various implementation details of CPython on a 64-bit system, one way to do this is as follows:

def modify_tuple(t, idx, new_value):
    # `id` happens to give the memory address in CPython; you may
    # want to use `ctypes.addressof` instead.
    element_ptr = (ctypes.c_longlong).from_address(id(t) + (3 + idx)*8)
    element_ptr.value = id(new_value)
    # Manually increment the reference count to `new_value` to pretend that
    # this is not a terrible idea.
    ref_count = (ctypes.c_longlong).from_address(id(new_value))
    ref_count.value += 1

t = (10, 20, 30)
modify_tuple(t, 1, 50)   # t is now (10, 50, 30)
modify_tuple(t, -1, 50)  # Will probably crash your Python runtime
Answered By: fuglede

Frist, ask yourself why you want to mutate your tuple. There is a reason why strings and tuple are immutable in Ptyhon, if you want to mutate your tuple then it should probably be a list instead.

Second, if you still wish to mutate your tuple then you can convert your tuple to a list then convert it back, and reassign the new tuple to the same variable. This is great if you are only going to mutate your tuple once. Otherwise, I personally think that is counterintuitive. Because It is essentially creating a new tuple and every time if you wish to mutate the tuple you would have to perform the conversion. Also If you read the code it would be confusing to think why not just create a list? But it is nice because it doesn’t require any library.

I suggest using mutabletuple(typename, field_names, default=MtNoDefault) from mutabletuple 0.2. I personally think this way is a more intuitive and readable. The personal reading the code would know that writer intends to mutate this tuple in the future. The downside compares to the list conversion method above is that this requires you to import additional py file.

from mutabletuple import mutabletuple

myTuple = mutabletuple('myTuple', 'v w x y z')
p = myTuple('275', '54000', '0.0', '5000.0', '0.0')
print(p.v) #print 275
p.v = '200' #mutate myTuple
print(p.v) #print 200

TL;DR: Don’t try to mutate tuple. if you do and it is a one-time operation convert tuple to list, mutate it, turn list into a new tuple, and reassign back to the variable holding old tuple. If desires tuple and somehow want to avoid listand want to mutate more than once then create mutabletuple.

Answered By: OLIVER.KOO

You can change the value of tuple using copy by reference

>>> tuple1=[20,30,40]

>>> tuple2=tuple1

>>> tuple2
    [20, 30, 40]

>>> tuple2[1]=10

>>> print(tuple2)
    [20, 10, 40]

>>> print(tuple1)
    [20, 10, 40]
Answered By: Rohit

It is possible with a one liner:

values = ('275', '54000', '0.0', '5000.0', '0.0')
values = ('300', *values[1:])
Answered By: Brian Spiering

I´m late to the game but I think the simplest, resource-friendliest and fastest way (depending on the situation),
is to overwrite the tuple itself. Since this would remove the need for the list & variable creation and is archived in one line.

new = 24
t = (1, 2, 3)
t = (t[0],t[1],new)

>>> (1, 2, 24)

But: This is only handy for rather small tuples and also limits you to a fixed tuple value, nevertheless, this is the case for tuples most of the time anyway.

So in this particular case it would look like this:

new = '200'
t = ('275', '54000', '0.0', '5000.0', '0.0')
t = (new, t[1], t[2], t[3], t[4])

>>> ('200', '54000', '0.0', '5000.0', '0.0')
Answered By: GordanTrevis

You can’t modify items in tuple, but you can modify properties of mutable objects in tuples (for example if those objects are lists or actual class objects)

For example

my_list = [1,2]
tuple_of_lists = (my_list,'hello')
print(tuple_of_lists) # ([1, 2], 'hello')
my_list[0] = 0
print(tuple_of_lists) # ([0, 2], 'hello')
Answered By: gunit

If you want to do this, you probably don’t want to toss a bunch of weird functions all over the place and call attention to you wanting to change values in things specific unable to do that. Also, we can go ahead and assume you’re not being efficient.

t = tuple([new_value if p == old_value else p for p in t])
Answered By: Tatarize
Categories: questions Tags: ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.