0

As I know a tuple is immutable structure, so if I have a list of tuples.

list1 = [(1,2,3,4),(2,3,4,5)]

and I have to change the first element of a tuple then I will have to basically write:

list1[0] = (2,2,3,4)     not list1[0][0] = 2 because tuple is immutable

For each element I need to do this. Is this an efficient operation or is it better to use a list of lists if this operation needs to be done regularly?

5
  • Actually even with a list of tuples you still can not change the tuple. You'd better use a list of lists. Commented Jul 19, 2013 at 15:45
  • Yes I know but you can always reassign the first element of the list which is the tuple to a new tuple like I have done above. I don't know how efficient it is. Commented Jul 19, 2013 at 15:47
  • 2
    If you need to do this for each element of your list, then use a list of lists. Commented Jul 19, 2013 at 15:48
  • Sukrit, is it more efficient to use a list of lists than to reassign one element of the list (which is a tuple) like list1[0] = (2,2,3,4) even when I know that the element is four dimensional? Won't list waste memory and tuple will be more efficient? Commented Jul 19, 2013 at 15:52
  • If you're asking about efficiency, the answer is to profile. Commented Jul 19, 2013 at 15:53

6 Answers 6

2

If you need to modify the elements of the list, then use mutable elements. Storing an immutable object in a mutable container does not make the object mutable.

As for efficiency, constructing a new tuple is more expensive than modifying a list. But readability is more important than runtime performance for most operations, so optimize for readability first. Also keep in mind that when the elements of a list of lists are referenced from the outside, you might get side-effects:

l1 = [1, 2, 3]
l2 = ['a', 'b', 'c']

lol = [l1, l2]
lol[0][0] = 0

print(l1)  # prints [0, 2, 3]

UPDATE: to back my claim of efficiency, here's some timings using IPython's %timeit magic:

>>> list_of_lists = [[1,2,3,4] for _ in xrange(10000)]
>>> list_of_tuples = map(tuple, list_of_lists)
>>> def modify_lol():
...     for x in list_of_lists:
...         x[0] = 0
...         
>>> def modify_lot():
...     for i, x in enumerate(list_of_tuples):
...         list_of_tuples[i] = (0,) + x[1:]
...         
>>> %timeit modify_lol()
100 loops, best of 3: 6.56 ms per loop
>>> %timeit modify_lot()
100 loops, best of 3: 17 ms per loop

So lists of lists are 2.6× faster for this task.

Sign up to request clarification or add additional context in comments.

2 Comments

Is it more efficient to use a list of lists than to reassign one element of the list (which is a tuple) like list1[0] = (2,2,3,4) even when I know that the element is four dimensional? Won't list waste memory and tuple will be more efficient??
@vkaul11: lists may take a little more memory. But are you processing large amounts of data? I.e. will you actually notice the difference?
0

Well looking at the direct solution you have the equivalent of

list[0] = (2,) + list[0] [1:]

Which should be enough to allow you to do it programmatically. It's still making a copy, but that's fairly quick, as is slicing the tuple.

Comments

0

If you define your variable like that:

list1 = [[1,2,3,4],[2,3,4,5]]

You will able to change the value of an elemento of a list like that:

list1[0][0] = 2

Now your variable value will be:

list1 = [[2,2,3,4],[2,3,4,5]]

Comments

0

The inefficently will come when you have to change ONLY a specific element. For instance say you had two tuples.

tup1 = (1, 2, 3, 4)
tup2 = (5, 6, 7, 8)

And you wanted to change the first element of both tuples to 9.

tup1 = (9, 2, 3, 4)
tup2 = (9, 6, 7, 8)

Is the only way to do that, if you had a million tuples with different values that all needed to start with 9 then this way is obviously inefficent, you will have to type and reassign all tuples different values.

Instead you should use a list.

l1 = [1, 2, 3, 4]
l2 = [5, 6, 7, 8]

Then you can do

list = [l1, l2]
for l in list:
    l[0] = 9

Which will change all the first elements to 9 without hardcoding a million lists.

l1 is now [9, 2, 3, 4]

l2 is now [9, 6, 7, 8]

Comments

0

You have two options:

L = [(1,2,3,4),(2,3,4,5)]
L = [tuple([2]+subL[1:]) for subL in L]

This is slower, as it has to recreate all those tuples.

OR

L = [(1,2,3,4),(2,3,4,5)]
L = [list(i) for i in L] # or L = map(list, L)
for subL in L:
    subL[0] = 2

Comments

0

If you know you'll only ever have four elements in your list items, but they need to be mutable, the best option (in my opinion) is to use a class:

class WXYZ: # example name, give yours something more sensible to the nature of the code
    def __init__(self, w=0, x=0, y=0, z=0)
        self.w = w
        self.x = x
        self.y = y
        self.z = z

Then your code will look something like:

list1 = [WXYZ(1,2,3,4), WXYZ(2,3,4,5)]
list1[0].w = 2

You can also easily add an __iter__ method if you need to use it in a for loop:

    def __iter__(self):
        return iter((w,x,y,z))

Alternatively, if you want to get clever, you can do

    def __iter__(self):
        yield w
        yield x
        yield y
        yield z

If you're really worried about memory usage (why are you using python in that case?), you can define __slots__ = ("w","x","y","z") to assign exactly as much memory as is required.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.