简体   繁体   中英

Efficient way to replace an element in a list of tuples by performing look up from another list (python)

I have a list of tuples, like so:

tuple_list = [(id-1,value-1),(id-2,value-2),....(id-n,value-n)]

Likewise, I have a list of objects that relates to the ids in the list above, ie:

object_list = [<obj-3>,<obj-1>,....<obj-n>]

Note that the order in object_list is different.

I'd like to generate a new list which is exactly like the first one above, except instead of id , it should have the object itself in it.Ie

resulting_list = [(<obj-1>,value-1),(<obj-2>,value-2),...(<obj-n>,value-n)]

What would be the most efficient way to perform this?


I'm trying it inside two for loops currently:

resulting_list = []
for tpl in tuple_list:
    for obj in object_list:
        if tpl[0] == obj.id
        resulting_list.append((obj,tpl[1]))

Construct a dict where keys are are object ids and values are objects. Then iterate over tuple_list within list comprehension and for each tuple output object from dict and value from original list:

class Obj:
    def __init__(self, id):
        self.id = id

    def __repr__(self):
        return 'Obj({})'.format(self.id)

tuple_list = [(0, 'Zero'), (1, 'One'), (2, 'Two'), (3, 'Three'), (4, 'Four')]
object_list = [Obj(i) for i in range(4, -1, -1)]

d = {o.id: o for o in object_list}
result = [(d[_id], val) for _id, val in tuple_list]

print(result)

Output:

[(Obj(0), 'Zero'), (Obj(1), 'One'), (Obj(2), 'Two'), (Obj(3), 'Three'), (Obj(4), 'Four')]

Time complexity of above is O(n) where as original code with nested loops is O(n^2) .

If your lists have length n then your current algorithm does n iterations on the outer loop, and n iterations on each inner loop, giving a total of n*n . You could improve that by breaking out of the inner loop as soon as you find a match. That will give an average of n*n/2 .

But it's better to do two loops each of length n , since for large n 2n is much smaller than n*n . In the code below, the first loop constructs a dictionary with the object id as the key and the object itself as the value. Then the second loop can quickly find the object from its id.

obj_map = {obj.id: obj for obj in object_list}
resulting_list = [(obj_map[k], v) for k, v in tuple_list]

If it's possible that some ids in tuple_list don't have a matching object in obj_map and you don't want to fail with a KeyError in that situation you can do

resulting_list = [(obj_map.get(k), v) for k, v in tuple_list]

which will supply None for any missing objects.

Alternatively,

resulting_list = [(obj_map.get(k, default_object), v) for k, v in tuple_list]

which will supply default_object for missing objects.

...
    i = object_list.index(tpl[0]) if tpl[0] in tuple_list else -1
    if i > -1:
      resulting_list.append((object_list[i],tpl[1]))

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