2012-02-14 10 views
6

にネストされた2つのリストを圧縮するための最も効率的な方法です:どのような単一レベルの辞書例えば

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

と私はこのような辞書にそれらをマージしたい:

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

私が持っていますこれを行う方法が、私はそれは時間がかかりすぎると思う:

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 

は、任意のより良いアイデアはありますか?

+0

あなたのソリューションは、以下の答えの全てよりも良く見えます。 – jterrace

答えて

1

あなたが提示したようなユースケース(ネストされたリストではあるが同じ形をしている)しかない場合は、まったく平らにする必要はないと思います。 10000回の実行で、

OPの方法:

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'} 

と方法の比較:ここでは、少なくとも私のマシン上(のみ再びその制約で動作します)あなたより2〜3倍高速であるアプローチがあります:0.290050983429

10000の実行上の他の提案された方法であって、0.580717086792

この方法で、10000回の実行に:0.155267000198

たぶんないよう他のソリューションと同じようにエレガントになりましたが、ここではパフォーマンスが主要な関心事に見えました。

+2

グローバル変数は、関数にパラメータとして渡すこともできます。リストの1つのみを反復するという考えは1回だけです。 – Bogdan

+0

これは本当に速いです。たぶんあなたは引数として "resultDict"を渡すことができます。 – BackMountainBird

5

私は機能平らのいくつかの種類を使用したい:

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 

を今、あなたは

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

を行うことができ、私はこの方法は、より一般的な読者のために、より透明性だと思います。以下のように定義flatten

+0

私はあなたのコードをテストしましたが、私のコードより2倍遅く実行されているようです。 – BackMountainBird

+3

'isinstance(it、collections.Iterable)'や 'hasattr(it、__iter __") 'を使って例外を避けるか、typeのiterablesに降順にするなど、flatten() 'list'。これらの変更のほとんどは、一般性や読みやすさに害を及ぼし、パフォーマンスを少し向上させます。パフォーマンスが本当に問題であれば、これは最適化する場所ではないと思われます。いずれにせよ、あなたが正しい場所で最適化されていることを確認する*プロファイル*。 –

+0

私はあなたのポイントを見ます。 – BackMountainBird

1

>>> 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)))はあなたと同じくらい速いのようです。そして、それははるかに便利なアプローチである、と男が言ったように。

+0

まだ私のコードよりも少し遅いです。 – BackMountainBird

0

私はスタックと発電機能を好き:

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))) 

結果:

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

それとも、あなたが入力リストが同じ構造を持っていることを確かに知っていれば、これもうまくいくかもしれない:

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

アイテムの順序が変更される可能性がありますのでご注意ください:

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

結果:

[1, 2, 3, 4, 5] 
[1, 2, 5, 3, 4] 
関連する問題