Накопить JSON значений в Python словаре как массив - PullRequest
3 голосов
/ 04 марта 2020

У меня есть JSON Файл в этом формате

{ 
"links": [
{"source":"0","target":"1","weight":1,"color":"white"},
{"source":"0","target":"2","weight":1,"color":"yellow"},
{"source":"0","target":"3","weight":1,"color":"white"},
]
}

Я хочу собрать все target для одного source, например:

{"source": 0, "neighbors": ["1","2","3"]} где neighbors все собранные target

Вот мой код

import json

with open("linksGr.json") as file:
    data = json.load(file)

collectDict = {}
for obj in data["links"]:
    if (collectDict["source"] == obj["source"]):
        collectDict["neighbour"] = obj["target"]

Мне просто нужен способ накапливать все цели для каждого источника вместо того, чтобы было несколько источников, как я сделал здесь

collectDict["source"] = obj["source"]
collectDict["neighbour"] = obj["target"]

Любая помощь будет принята с благодарностью. Я уверен, что есть какая-то базовая c концепция и простой способ, который мне здесь не хватает. Спасибо за помощь.

Ответы [ 3 ]

4 голосов
/ 04 марта 2020

Если я правильно вас понимаю, вы можете использовать collections.defaultdict, чтобы отобразить из источника список целей, например:

(я добавил некоторые данные имеют несколько источников)

from collections import defaultdict

data = { 
"links": [
{"source":"0","target":"1","weight":1,"color":"white"},
{"source":"0","target":"2","weight":1,"color":"yellow"},
{"source":"0","target":"3","weight":1,"color":"white"},
{"source":"5","target":"7","weight":1,"color":"white"},
{"source":"5","target":"8","weight":1,"color":"yellow"},
{"source":"6","target":"9","weight":1,"color":"white"},
]
}

collectDict = defaultdict(list)
for obj in data["links"]:
    collectDict[obj["source"]].append(obj["target"])

print(dict(collectDict))

Вывод:

{'0': ['1', '2', '3'], '5': ['7', '8'], '6': ['9']}

РЕДАКТИРОВАТЬ: Вот еще один метод с использованием itertools.groupby, при условии, что ссылки упорядочены по источникам (в противном случае, просто отсортируйте их раньше)

from itertools import groupby

collectDict = {k: [t["target"] for t in g] for k,g in groupby(data["links"], lambda obj: obj["source"])}

print(collectDict)
1 голос
/ 04 марта 2020
data = { 
    "links": [
        {"source":"0","target":"1","weight":1,"color":"white"},
        {"source":"0","target":"2","weight":1,"color":"yellow"},
        {"source":"0","target":"3","weight":1,"color":"white"},
        {"source":"5","target":"7","weight":1,"color":"white"},
        {"source":"5","target":"8","weight":1,"color":"yellow"},
        {"source":"6","target":"9","weight":1,"color":"white"},
    ]
}

collected = []
for obj in data["links"]:
    source_matches = [item for item in collected if item["source"] == obj["source"]]
    if len(source_matches) == 0:
        source_match = {"source": obj["source"], "neighbour": [obj["target"]]}
        collected.append(source_match)
    elif len(source_matches) == 1:
        source_matches[0]["neighbour"].append(obj["target"])
    else:
        raise BaseException()

print(collected)  # [{'source': '0', 'neighbour': ['1', '2', '3']}, {'source': '5', 'neighbour': ['7', '8']}, {'source': '6', 'neighbour': ['9']}]

Не очень элегантно, но выполняет свою работу.

Если вам действительно не нужен формат {"source": 0, "neighbors": ["1","2","3"]} Я рекомендую вышеуказанное решение с использованием defaultdict. Если вам нужен этот формат, вы также можете создать его из вывода решения defaultdict.

0 голосов
/ 04 марта 2020

Вот простое решение:

import pandas as pd

result = [{"source": source, "neighbors": df["target"].tolist()}
          for source, df in pd.DataFrame(data["links"]).groupby("source")]
...