Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Python - Update a value in a list of tuples

Tags:

python

What is the best way to update a value in a list of tuples?

I currently do it like in the code below, but I suppose there is a cleaner and concise way.

>>> foo = [('a', 'hello'), ('b', 'world')]
>>> bar = dict(foo)
>>> bar['b'] = 'friend'
>>> foo = bar.items()
>>> foo
[('a', 'hello'), ('b', 'friend')]

Edit: The reason to use a list of tuple wasn't clear in my original post. The goal is to update some headers values of a wsgi application during error handling, that are a list of tuples.

Thanks in advance.

like image 309
Eric Avatar asked Dec 19 '11 09:12

Eric


People also ask

How do you change a tuple value in a list?

Once a tuple is created, you cannot change its values. Tuples are unchangeable, or immutable as it also is called. But there is a workaround. You can convert the tuple into a list, change the list, and convert the list back into a tuple.

Can we update items from tuple in Python?

Tuples are unchangeable, meaning that you cannot change, add, or remove items once the tuple is created.

How do you update index value in tuple?

First, convert tuple to list by built-in function list(). You can always update an item to list object assigning new value to element at certain index. Then use another built-in function tuple() to convert this list object back to tuple. Element at index 4 in original tuple has been changed from 25 to 100.


4 Answers

Your data structure (a list of tuple) is best referred as an associative list. As other pointed out, it is probably better to use a dictionary as you'll get better amortized cost on operation (insertion, deletion, and lookup are O(1) for a dictionary, but deletion and lookup are O(n) for associative list).

Concerning updating your associative list by converting it to a dictionary, and then back to an associative list, this method has three drawbacks. It is quite expensive, it may change the order of the items, and it will remove duplicate.

If you want to keep using associative lists, it is probably better to just use a list comprehension to update the data structure. The cost will be O(n) in time and memory, but that's already what you have when using an intermediate dictionary.

Here's a simple way to do it (require Python 2.5 because it use the ternary operator):

def update_in_alist(alist, key, value):
    return [(k,v) if (k != key) else (key, value) for (k, v) in alist]

def update_in_alist_inplace(alist, key, value):
    alist[:] = update_in_alist(alist, key, value)

>>> update_in_alist([('a', 'hello'), ('b', 'world')], 'b', 'friend')
[('a', 'hello'), ('b', 'friend')]
like image 166
Sylvain Defresne Avatar answered Oct 03 '22 15:10

Sylvain Defresne


Since tuples are immutable, you'll need to replace the tuple with a new one.

>>> foo[1] = (foo[1][0], "friend")
>>> foo
[('a', 'hello'), ('b', 'friend')]

Of course, this only works if you know the index of the item you wish to replace. If all you have is the value of the first item, then searching through the list for that index is not efficient especially for larger lists. The same goes for your example above -- converting a list to a dict and back just to change a few entries is not a scalable solution.

As eumiro and DrTysra mentioned in the comments, if your data structure allows it, you might be better off simply using a dict (or OrderedDict if order is important).

like image 20
Shawn Chin Avatar answered Oct 03 '22 14:10

Shawn Chin


From your usage, it seems you really want to use a dictionary to begin with, not a list of tuples. If you're treating the first field of each tuple as a unique key, make it a dictionary so you get O(1) access and validation that the keys are really unique.

Otherwise, you need to search to find the index of the tuple to modify, and then overwrite that slot in the array with a new tuple, since tuples themselves cannot be modified.

index = -1
target = "b"
new_value = "friend"
for i, v in enumerate(foo):
  if v[0] == target:
    index = i
    break
if index >= 0:
  foo[index] = (foo[index][0], new_value)

This is, admittedly, a bit clumsy but otherwise straight-forward and should at least be a bit faster (and less memory-hungry) than your current solution. It can trivially be wrapped into a function to encapsulate it, of course.

like image 34
unwind Avatar answered Oct 03 '22 14:10

unwind


It's not perfectly clear to me what you want to achieve. Tuples cannot be modified, so you cannot change ('b', 'world') to something else. But you can modify the list of course:

foo[1] = ('b','friend')

Whether that makes sense or not depends on your use case. If you give us more details about the actual purpose of the code, we would be able to propose better solutions.

like image 26
Achim Avatar answered Oct 03 '22 15:10

Achim