programing

목록의 dicts에서 dict로/dict 목록

padding 2023. 4. 23. 10:08
반응형

목록의 dicts에서 dict로/dict 목록

(같은 길이의) 목록 사전 간에 앞뒤로 변경하려고 합니다.

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

및 사전 목록:

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

영리하고 해키한 원라이너를 좋아하는 분들을 위해.

여기 있습니다DL로.LD:

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

그리고.LD로.DL:

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

LD로.DL각각의 키가 동일하다고 가정하기 때문에 조금 더 해킹이 가능합니다.dict또, 이러한 코드를 실제 시스템에 사용하는 것은 용납할 수 없습니다.

외부 패키지 사용이 허용된다면 Panda는 다음과 같은 작업을 수행할 수 있습니다.

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

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

사전 목록에서 간단하게 설명하겠습니다.

다음 양식을 사용할 수 있습니다.

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

다른 길로 가는 것은 문제가 있다.사전의 키에서 목록에 삽입 순서에 대한 정보가 필요합니다.dict의 키 순서가 원래 삽입 순서와 같을 필요는 없습니다.

킥킥의 경우 삽입 순서가 정렬된 키를 기반으로 한다고 가정합니다.그런 다음 다음과 같이 수행할 수 있습니다.

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

이것을 리스트의 딕트로 되돌리는 방법은 다음과 같습니다.

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 3 대신 Python 2를 사용하는 경우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]}

비사이톤 버전

문서

from toolz.dicttoolz import merge_with

merge_with(list, *LD)

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

의 python 모듈pandas알기 쉬운 솔루션을 제공합니다.@chiang의 답변을 보완하기 위해 D-to-L과 L-to-D의 솔루션은 다음과 같습니다.

import pandas as pd
DL = {'a': [0, 1], 'b': [2, 3]}
out1 = pd.DataFrame(DL).to_dict('records')

출력:

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

반대 방향:

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

출력:

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

여름의 금요일을 생각하기에 가장 깔끔한 방법이야.단, 이 case of른른른른른((((((((((((((((, (((((((( as as as as as as as as as as as as as as,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. dict에서 목록으로

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

여기 내 작은 스크립트:

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

발전기를 사용해도 괜찮으시다면

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

기술적인 이유 때문에 '깨끗한' 것은 아닙니다.은 초초장실 my my my my my my my my my my my my,yield dict(...) (2. Python 2.5에서는 빈 a for b in c는 StopIteration을 통해 할 때 하지 않습니다.c StopIteration 시 (')a.

한편, 실제로 무엇을 하려고 하는지는 알 수 없습니다.기존의 데이터 구조에 짜넣는 것이 아니라, 요구에 맞는 데이터 구조를 설계하는 것이 현명할 수 있습니다(예를 들면, dicts 리스트는 데이터베이스 쿼리의 결과를 나타내는 빈약한 방법입니다).

dicts dict dict of lists 목록

from collections import defaultdict
from typing import TypeVar

K = TypeVar("K")
V = TypeVar("V")


def ld_to_dl(ld: list[dict[K, V]]) -> dict[K, list[V]]:
    dl = defaultdict(list)
    for d in ld:
        for k, v in d.items():
            dl[k].append(v)
    return dl

defaultdict 키 접근 시 빈 목록이 존재하지 않는 경우 에 의해 빈 목록이 생성됩니다.


목록의 딕트 » 딕트 목록

"jagged" 사전 수집

from typing import TypeVar

K = TypeVar("K")
V = TypeVar("V")


def dl_to_ld(dl: dict[K, list[V]]) -> list[dict[K, V]]:
    ld = []
    for k, vs in dl.items():
        ld += [{} for _ in range(len(vs) - len(ld))]
        for i, v in enumerate(vs):
            ld[i][k] = v
    return ld

하면 사전 됩니다.ld될 수 .dl불평등합니다.의 모든 키 값에 루프가 발생합니다.dl및 빈 사전을 만듭니다.ld충분하지 않습니다.

"완전한" 사전에만 수집

(통상은 같은 길이의 리스트만을 대상으로 하고 있습니다).

from typing import TypeVar

K = TypeVar("K")
V = TypeVar("V")


def dl_to_ld(dl: dict[K, list[V]]) -> list[dict[K, V]]:
    ld = [dict(zip(dl.keys(), v)) for v in zip(*dl.values())]
    return ld

하면 사전 됩니다.ld 것.dl.

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

언급URL : https://stackoverflow.com/questions/5558418/list-of-dicts-to-from-dict-of-lists

반응형