What is the most efficient way to pin two nested lists in the same dictionary level

eg:

list1=['k1','k2','k3',['k4','k5',['k6','k7']]] list2=['v1','v2','v3',['v4','v5',['v6','v7']]] 

and I want to combine them with the following dictionary:

 dict1={'k1':'v1','k2':'v2','k3':'v3','k4':'v4','k5':'v5','k6':'v6','k7':'v7'} 

I have a way to do this, but I think it takes too much time:

 def mergeToDict(keyList, valueList): resultDict = {} for key, value in itertools.izip(keyList, valueList): if type(key) == list and type(value) == list: resultDict=dict(resultDict,**mergeToDict(key, value)) elif type(key) != list and type(key) != dict and type(key) != tuple: resultDict[key] = value return resultDict 

Are there any better ideas?

+6
source share
4 answers

I donโ€™t think you need to smooth out at all if you only have cases like the ones that you presented (nested lists, but with the same shape). Here is an approach that is at least 2-3 times faster than yours on my machine (again, it works only with this limitation):

 def appendDict(list1, list2, resultDict): for idx, val in enumerate(list1): if isinstance(val, list): appendDict(val, list2[idx], resultDict) else: resultDict[val] = list2[idx] list1=['k1','k2','k3',['k4','k5',['k6','k7']]] list2=['v1','v2','v3',['v4','v5',['v6','v7']]] resultDict = {} appendDict(list1, list2, resultDict) print resultDict {'k3': 'v3', 'k2': 'v2', 'k1': 'v1', 'k7': 'v7', 'k6': 'v6', 'k5': 'v5', 'k4': 'v4'} 

And a comparison of the methods:

OP method, per 10000 runs: 0.290050983429

Another suggested method for 10,000 runs: 0.580717086792

This method, for 10,000 runs: 0.155267000198

It may not be as elegant as other solutions, but performance seems to have been the main issue here.

+1
source

I would use some kind of smoothing function:

 def flatten(it): if isinstance(it, str): yield it return try: for x in it: for y in flatten(x): yield y except TypeError: yield it 

Now you can do

 from itertools import izip my_dict = dict(izip(flatten(list1), flatten(list2))) 

I think this method is more general and more transparent to the reader.

+5
source

With flatten is defined as:

 >>> def flatten(l): ... r = [] ... for x in l: ... if isinstance(x, list): ... r.extend(flatten(x)) ... else: ... r.append(x) ... return r 

dict(zip(flatten(list1), flatten(list2))) seems as fast as yours. And this is a much more convenient approach, as the guys said.

+1
source

I like the stacks and functions of the generator:

 def flatten(seq, *seq_types): stack = [iter(seq)] while stack: for item in stack[-1]: if isinstance(item, seq_types): stack.append(iter(item)) break else: yield item else: stack.pop() keys = [0, 1, (2, 3, [4.])] values = (5, 6, (7, "joe", [9])) print dict(zip(flatten(keys, list, tuple), flatten(values, tuple, list))) 

Result:

 {0: 5, 1: 6, 2: 7, 3: 'joe', 4.0: 9} 

Or, if you know for sure that the input lists have the same structure, this may also work:

 def flatten(seq, *seq_types): seq = list(seq) for item in seq: if isinstance(item, seq_types): seq.extend(item) else: yield item 

Beware of reordering elements:

 print list(flatten([1, 2, [3, 4, [5]]], list)) print list(flatten([1, 2, [[3, 4], 5]], list)) 

Result:

 [1, 2, 3, 4, 5] [1, 2, 5, 3, 4] 
0
source

Source: https://habr.com/ru/post/908430/


All Articles