簡體   English   中英

字典列表到/來自列表字典

[英]List of dicts to/from dict of lists

我希望在列表字典(長度相同)之間來回更改:

DL = {'a': [0, 1], 'b': [2, 3]}

和字典列表:

LD = [{'a': 0, 'b': 2}, {'a': 1, 'b': 3}]

我正在尋找在兩種形式之間切換的最干凈的方式。

對於那些喜歡聰明/hacky one-liners的人。

這是DLLD

v = [dict(zip(DL,t)) for t in zip(*DL.values())]
print(v)

LDDL

v = {k: [dic[k] for dic in LD] for k in LD[0]}
print(v)

LDDL有點麻煩,因為您假設每個dict中的鍵都相同。 另外,請注意,我不容忍在任何類型的真實系統中使用此類代碼。

也許考慮使用 numpy:

import numpy as np

arr = np.array([(0, 2), (1, 3)], dtype=[('a', int), ('b', int)])
print(arr)
# [(0, 2) (1, 3)]

在這里,我們訪問按名稱索引的列,例如'a''b' (有點像DL ):

print(arr['a'])
# [0 1]

這里我們通過整數索引訪問行(有點像LD ):

print(arr[0])
# (0, 2)

行中的每個值都可以通過列名訪問(有點像LD ):

print(arr[0]['b'])
# 2

如果你被允許使用外部包,Pandas 非常適合:

import pandas as pd
pd.DataFrame(DL).to_dict(orient="records")

哪些輸出:

[{'a': 0, 'b': 2}, {'a': 1, 'b': 3}]

您也可以使用orient="list"找回原始結構

{'a': [0, 1], 'b': [2, 3]}

從字典列表中,很簡單:

您可以使用此表格:

DL={'a':[0,1],'b':[2,3], 'c':[4,5]}
LD=[{'a':0,'b':2, 'c':4},{'a':1,'b':3, 'c':5}]

nd={}
for d in LD:
    for k,v in d.items():
        try:
            nd[k].append(v)
        except KeyError:
            nd[k]=[v]

print nd     
#{'a': [0, 1], 'c': [4, 5], 'b': [2, 3]}

或使用defaultdict

nd=cl.defaultdict(list)
for d in LD:
   for key,val in d.items():
      nd[key].append(val)

print dict(nd.items())
#{'a': [0, 1], 'c': [4, 5], 'b': [2, 3]}

走另一條路是有問題的。 您需要從字典中的鍵中獲得一些插入順序的信息到列表中。 回想一下,字典中鍵的順序不一定與原始插入順序相同。

對於笑聲,假設插入順序基於排序的鍵。 然后你可以這樣做:

nl=[]
nl_index=[]

for k in sorted(DL.keys()):
    nl.append({k:[]})
    nl_index.append(k)

for key,l in DL.items():
    for item in l:
        nl[nl_index.index(key)][key].append(item)

print nl        
#[{'a': [0, 1]}, {'b': [2, 3]}, {'c': [4, 5]}]

如果您的問題是基於好奇心,那么這就是您的答案。 如果您遇到實際問題,我建議您重新考慮您的數據結構。 這些似乎都不是一個非常可擴展的解決方案。

以下是我提出的單行解決方案(為了可讀性而分散在多行上):

如果 dl 是您的原始列表字典:

dl = {"a":[0, 1],"b":[2, 3]}

然后這里是如何將其轉換為字典列表:

ld = [{key:value[index] for key,value in dl.items()}
         for index in range(max(map(len,dl.values())))]

其中,如果您假設所有列表的長度相同,則可以通過以下方式簡化並提高性能:

ld = [{key:value[index] for key, value in dl.items()}
        for index in range(len(dl.values()[0]))]

如果dl包含不對稱列表,則以下工作正常:

from itertools import product

dl = {"a":[0, 1],"b":[2, 3, 4], "c":[5, 6, 7, 8]}

ld = [dict(zip(dl.keys(), items)) 
        for items in product(*(dl.values()))]

以下是將其轉換回列表字典的方法:

dl2 = {key:[item[key] for item in ld]
         for key in list(functools.reduce(
             lambda x, y: x.union(y),
             (set(dicts.keys()) for dicts in ld)
         ))
      }

如果您使用的是 Python 2 而不是 Python 3,您可以在那里使用reduce而不是functools.reduce

如果您假設列表中的所有字典都具有相同的鍵,則可以簡化此操作:

dl2 = {key:[item[key] for item in ld] for key in ld[0].keys() }

cytoolz.dicttoolz.merge_with

文檔

from cytoolz.dicttoolz import merge_with

merge_with(list, *LD)

{'a': [0, 1], 'b': [2, 3]}

非cython版本

文檔

from toolz.dicttoolz import merge_with

merge_with(list, *LD)

{'a': [0, 1], 'b': [2, 3]}

pandas的python模塊可以給你一個通俗易懂的解決方案。 作為@chiang回答的補充,D-to-L和L-to-D的解決方案如下:

In [1]: import pandas as pd

In [2]: DL = {'a': [0, 1], 'b': [2, 3]}

In [3]: pd.DataFrame(DL).to_dict('records')
Out[3]: [{'a': 0, 'b': 2}, {'a': 1, 'b': 3}]

In [4]: LD = [{'a': 0, 'b': 2}, {'a': 1, 'b': 3}]

In [5]: pd.DataFrame(LD).to_dict('list')
Out[5]: {'a': [0, 1], 'b': [2, 3]}

我能想到的最干凈的方式是夏天的星期五。 作為獎勵,它支持不同長度的列表(但在這種情況下, DLtoLD(LDtoDL(l))不再是身份)。

  1. 從列表到字典

    實際上不如@dwerk 的 defaultdict 版本干凈。

     def LDtoDL (l) : result = {} for d in l : for k, v in d.items() : result[k] = result.get(k,[]) + [v] #inefficient return result
  2. 從字典到列表

    def DLtoLD (d) : if not d : return [] #reserve as much *distinct* dicts as the longest sequence result = [{} for i in range(max (map (len, d.values())))] #fill each dict, one key at a time for k, seq in d.items() : for oneDict, oneValue in zip(result, seq) : oneDict[k] = oneValue return result

這是一個沒有使用任何庫的解決方案:

def dl_to_ld(initial):
    finalList = []
    neededLen = 0

    for key in initial:
        if(len(initial[key]) > neededLen):
            neededLen = len(initial[key])

    for i in range(neededLen):
        finalList.append({})

    for i in range(len(finalList)):
        for key in initial:
            try:
                finalList[i][key] = initial[key][i]
            except:
                pass

    return finalList

您可以按如下方式調用它:

dl = {'a':[0,1],'b':[2,3]}
print(dl_to_ld(dl))

#[{'a': 0, 'b': 2}, {'a': 1, 'b': 3}]

這是我的小腳本:

a = {'a': [0, 1], 'b': [2, 3]}
elem = {}
result = []

for i in a['a']: # (1)
    for key, value in a.items():
        elem[key] = value[i]
    result.append(elem)
    elem = {}

print result

我不確定那是一種美麗的方式。

(1)您假設列表的長度相同

如果你不介意發電機,你可以使用類似

def f(dl):
  l = list((k,v.__iter__()) for k,v in dl.items())
  while True:
    d = dict((k,i.next()) for k,i in l)
    if not d:
      break
    yield d

由於技術原因,它不像它可能的那樣“干凈”:我的原始實現確實yield dict(...) ,但這最終成為空字典,因為(在 Python 2.5 中) a for b in c不區分 a迭代c的 StopIteration 異常和評估a時的 StopIteration 異常。

另一方面,我無法弄清楚你真正想要做什么; 設計一種滿足您要求的數據結構而不是試圖將其硬塞到現有數據結構中可能更明智。 (例如,字典列表是表示數據庫查詢結果的一種糟糕方式。)

我需要一種適用於不同長度列表的方法(所以這是原始問題的概括)。 由於我沒有在這里找到任何符合我預期的代碼,這里是我的代碼,它對我有用:

def dict_of_lists_to_list_of_dicts(dict_of_lists: Dict[S, List[T]]) -> List[Dict[S, T]]:
    keys = list(dict_of_lists.keys())
    list_of_values = [dict_of_lists[key] for key in keys]
    product = list(itertools.product(*list_of_values))

    return [dict(zip(keys, product_elem)) for product_elem in product]

例子:

>>> dict_of_lists_to_list_of_dicts({1: [3], 2: [4, 5]})
[{1: 3, 2: 4}, {1: 3, 2: 5}]
>>> dict_of_lists_to_list_of_dicts({1: [3, 4], 2: [5]})
[{1: 3, 2: 5}, {1: 4, 2: 5}]
>>> dict_of_lists_to_list_of_dicts({1: [3, 4], 2: [5, 6]})
[{1: 3, 2: 5}, {1: 3, 2: 6}, {1: 4, 2: 5}, {1: 4, 2: 6}]
>>> dict_of_lists_to_list_of_dicts({1: [3, 4], 2: [5, 6], 7: [8, 9, 10]})
[{1: 3, 2: 5, 7: 8},
 {1: 3, 2: 5, 7: 9},
 {1: 3, 2: 5, 7: 10},
 {1: 3, 2: 6, 7: 8},
 {1: 3, 2: 6, 7: 9},
 {1: 3, 2: 6, 7: 10},
 {1: 4, 2: 5, 7: 8},
 {1: 4, 2: 5, 7: 9},
 {1: 4, 2: 5, 7: 10},
 {1: 4, 2: 6, 7: 8},
 {1: 4, 2: 6, 7: 9},
 {1: 4, 2: 6, 7: 10}]
DL={'a':[0,1,2,3],'b':[2,3,4,5]}
LD=[{'a':0,'b':2},{'a':1,'b':3}]
Empty_list = []
Empty_dict = {}
# to find length of list in values of dictionry
len_list = 0
for i in DL.values():
    if len_list < len(i):
        len_list = len(i)

for k in range(len_list):        
    for i,j in DL.items():
        Empty_dict[i] = j[k]
    Empty_list.append(Empty_dict)
    Empty_dict = {}
LD = Empty_list

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM