2012-02-14 52 views
6

例如最有效的方法:什麼是壓縮兩個嵌套列表單級字典

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 2012-02-14 14:24:21

回答

1

如果你只有像你提交的用例(嵌套列表,但形狀相同),我不認爲你需要扁平化。這裏是一個辦法,至少在我的機器比你快2-3倍(僅再次與約束作品):

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

和方法進行了比較:

OP的方法,在運行10000 :0.290050983429

其他提出的方法,對10000個運行:0.580717086792

這種方法,在10000個運行:0.155267000198

也許不是與其他解決方案一樣優雅,但表現似乎是這裏的主要關注點。

+2

全局變量可以像參數一樣傳遞給函數,它的思想是它只在一個列表上迭代,並且只做一次。 – Bogdan 2012-02-14 14:27:22

+0

這真的很快。也許你可以通過「resultDict」作爲參數,看起來更好。 – BackMountainBird 2012-02-14 14:28:53

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

我覺得這種方式是比較普遍和讀者更加透明。

+0

我測試了你的代碼,但它似乎比我的代碼慢兩倍。 – BackMountainBird 2012-02-14 13:28:38

+3

'flatten()'函數有優化的空間 - 例如通過使用'isinstance(it,collections.Iterable)'或'hasattr(it,「__iter __」)'來避免異常,或者只降序到iterable 'list'。這些變化中的大部分都會損害通用性或可讀性以獲得一點性能。如果性能確實是一個問題,我懷疑這是優化的地方 - 而是首先改變這些列表的創建方式。無論如何,* profile *以確保你在正確的地方進行了優化。 – 2012-02-14 14:00:32

+0

我明白你的觀點。 – BackMountainBird 2012-02-14 14:15:03

1

隨着flatten定義爲:

>>> 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 2012-02-14 14:02:51

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]