简体   繁体   中英

Possible to modify every first tuple element in a list of tuples?

I need your help, I have a structure like this:

myList = [(1,2,3),(2,4,4),(1,5,6)]

It's a list of tuples. Now I need to get every first element of each tuple in the list to eg replace each 1 with a 3 .

The output should be: myList = [(3,2,3),(2,4,4),(3,5,6)]

I know I can make it like:

for item in myList:
   if item[0] == 1:
      item[0] = 3

But is there a other way to do this? Without iterating over the whole list?

Something like: myList.getFirstItemOfEachTuple.replace(1,3)

EDIT: I could change the myList to [[1,2,3,4,5,6]...] if necessary.

>>> myList = [(1,2,3,4,5,6),(4,5,6,7,8)]
>>> dic = {1:3}
>>> [ (dic.get(x[0],x[0]),) + x[1:] for x in myList]
[(3, 2, 3, 4, 5, 6), (4, 5, 6, 7, 8)]

If myList is a list of lists:

>>> myList = [[1,2,3,4,5,6],[4,5,6,7,8]]
>>> [ [dic.get(x[0],x[0]) ] + x[1:] for x in myList]
[[3, 2, 3, 4, 5, 6], [4, 5, 6, 7, 8]]

to modify the original list:

>>> myList[:] = [(dic.get(x[0],x[0]),) + x[1:] for x in myList]
>>> myList
[(3, 2, 3, 4, 5, 6), (4, 5, 6, 7, 8)]

But is there a other way to do this? without iterating over the whole list?

No. Not without iterating over the whole list.

Since you wish to examine each tuple to see if the element you wish to change is a certain number, you have to iterate over the whole list somehow . So the only remaining consideration is how to do it.

There exist good, time-tested and industry-standard guidelines that help decide how to write code: when writing code you should have code readability as a first priority. Code efficiency comes in as a distant second. There are exceptions to this rule, but they're not relevant here.

Look at your original code. It assumes item is a list , so I will too:

for item in myList:
    if item[0] == 1:
        item[0] = 3

Now compare with Ashwini's suggestion:

dic = {1: 3}
myList[:] = [[dic.get(x[0], x[0])] + x[1:] for x in myList]

Now ask yourself:

  • Which one is easiest to read and understand? I think the answer is obvious.
  • Which one is more efficient?

Let's look at the efficiency:

  • Your original code: For each item in myList , perform a single list lookup and then possibly a single list assignment, both extremely fast operations.

  • Ashwinis code: Rebuild the entire structure. For each item in myList python needs to create three new lists ( five if you want to change an item that's not the first). Python must allocate new memory for each list and garbage collect a lot of old lists, both rather slow operations. All for the sake of cramming it into a one-liner.

Please , go with your original code. Here's why:

  • It's the obvious way to do it.
  • It's the pythonic way to do it.
  • It's the most readable way to do it.
  • It's the most efficient way to do it.

Which means it's the right way to do it.

If you want a one-liner, make it a function:

def conditional_sublist_assign(myList, index, from, to):
    """
    For each `item` in `myList`, set `item[index] = to` if `item[index] == from`.
    """
    for item in myList:
        if item[index] == from:
            item[index] = to

# Here's your one-liner:
conditional_sublist_assign(myList, 0, 1, 3)

To lend some more weight to my arguments, here are some relevant lines from The Zen of Python :

  • Beautiful is better than ugly.
  • Simple is better than complex.
  • Readability counts.
  • There should be one-- and preferably only one --obvious way to do it.
  • If the implementation is hard to explain, it's a bad idea.

With list comprehensions.

Condition first tuple item must be 1:

>>> L = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
>>> [[3] + x[1:] if x[0] == 1 else x for x in L]
[[3, 2, 3], [4, 5, 6], [7, 8, 9]]

Solution for tuples instead of lists inside the list:

>>> L = [(1, 2, 3), (4, 5, 6), (7, 8, 9)]
>>> [(3,)  + x[1:] if x[0] == 1 else x  for x in L]
[(3, 2, 3), (4, 5, 6), (7, 8, 9)]

you can do that in numpy, numpy is also 50 times faster than python so if speed is important, that is definatly the way to go:

import numpy as np
myList = [(1,2,3),(2,4,4),(1,5,6)]
# convert list of tuples to 2D numpy array
myList = np.array(myList)
# get an array of all first element, syntax: myList[x, y] x and w and be ranges 1:3 og numbers like 1
# all the first elements are as follows:
first = myList[:,0]
# you can then make a true / false vector as follows
myList[first == 1,0] = 3
print myList
# prints:
#[[3 2 3]
# [2 4 4]
# [3 5 6]]

you can't change the value of tuple, it's immutable. But you convert tuple to list and change the value

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM