Используя .values ​​() со списком словарей? - PullRequest
0 голосов
/ 12 ноября 2018

Я сравниваю файлы json между двумя разными конечными точками API, чтобы увидеть, какие записи json нуждаются в обновлении, которые требуют создания, а какие - удаления. Итак, сравнивая два файла json, я хочу получить три файла json, по одному для каждой операции.

JSON на обеих конечных точках структурирован следующим образом (но они используют разные ключи для одинаковых наборов значений; разные проблемы):

{
    "records": [{
        "id": "id-value-here",
        "c": {
            "d": "eee"
        },
        "f": {
            "l": "last",
            "f": "first"
        },
        "g": ["100", "89", "9831", "09112", "800"]
    }, {

        …


    }]
}

Таким образом, json представлен в виде списка словарей (с дополнительными вложенными списками и словарями).

Если заданное значение идентификатора конечной точки json (j1) («id» :) существует в другой конечной точке json (j2), то эта запись должна быть добавлена ​​в j_update.

Пока что у меня есть что-то подобное, но я вижу, что .values ​​() не работает, потому что пытается работать со списком, а не со всеми перечисленными словарями (?):

j_update = {r for r in j1['records'] if r['id'] in 
j2.values()}

Это не возвращает ошибку, но создает пустой набор, используя тестовые файлы json.

Похоже, это должно быть просто, но я думаю о словарях в списке, представляющих json. Мне нужно сплющить j2, или есть простой способ словаря Python для достижения этого?

==== редактировать j1 и j2 ==== иметь одинаковую структуру, использовать разные ключи; данные игрушки

j1

{
    "records": [{
        "field_5": 2329309841,
        "field_12": {
            "email": "cmix@etest.com"
        },
        "field_20": {
            "last": "Mixalona",
            "first": "Clara"
        },
        "field_28": ["9002329309999", "9002329309112"],
        "field_44": ["1002329309832"]
    }, {
        "field_5": 2329309831,
        "field_12": {
            "email": "mherbitz345@test.com"
        },
        "field_20": {
            "last": "Herbitz",
            "first": "Michael"
        },
        "field_28": ["9002329309831", "9002329309112", "8002329309999"],
        "field_44": ["1002329309832"]
    }, {
        "field_5": 2329309855,
        "field_12": {
            "email": "nkatamaran@test.com"
        },
        "field_20": {
            "first": "Noriss",
            "last": "Katamaran"
        },
        "field_28": ["9002329309111", "8002329309112"],
        "field_44": ["1002329309877"]
    }]
}

j2

{
    "records": [{
        "id": 2329309831,
        "email": {
            "email": "mherbitz345@test.com"
        },
        "name_primary": {
            "last": "Herbitz",
            "first": "Michael"
        },
        "assign": ["8003329309831", "8007329309789"],
        "hr_id": ["1002329309877"]
    }, {
        "id": 2329309884,
        "email": {
            "email": "yinleeshu@test.com"
        },
        "name_primary": {
            "last": "Lee Shu",
            "first": "Yin"
        },
        "assign": ["8002329309111", "9003329309831", "9002329309111", "8002329309999", "8002329309112"],
        "hr_id": ["1002329309832"]
    }, {
        "id": 23293098338,
        "email": {
            "email": "amlouis@test.com"
        },
        "name_primary": {
            "last": "Maxwell Louis",
            "first": "Albert"
        },
        "assign": ["8002329309111", "8007329309789", "9003329309831", "8002329309999", "8002329309112"],
        "hr_id": ["1002329309877"]
    }]
}

Ответы [ 2 ]

0 голосов
/ 21 марта 2019

Вы пробовали:

j_update = {r for r in j1['records'] if r['id'] in j2.values()}

Помимо проблемы r['id'/'field_5], у вас есть:

>>> list(j2.values())
[[{'id': 2329309831, ...}, ...]]

id скрыты внутри списка и вхождения, поэтому тест r['id'] in j2.values() всегда возвращает False.

Основное решение довольно простое. Сначала создайте набор из j2 id s:

>>> present_in_j2 = set(record["id"] for record in j2["records"])

Затем перестройте структуру json из j1, но без j1 field_5, которого нет в j2:

>>> {"records":[record for record in j1["records"] if record["field_5"] in present_in_j2]}
{'records': [{'field_5': 2329309831, 'field_12': {'email': 'mherbitz345@test.com'}, 'field_20': {'last': 'Herbitz', 'first': 'Michael'}, 'field_28': ['9002329309831', '9002329309112', '8002329309999'], 'field_44': ['1002329309832']}]}

Это работает, но не совсем удовлетворительно из-за странных ключей j1. Давайте попробуем преобразовать j1 в более дружественный формат:

def map_keys(json_value, conversion_table):
    """Map the keys of a json value
    This is a recursive DFS"""

    def map_keys_aux(json_value):
        """Capture the conversion table"""
        if isinstance(json_value, list):
            return [map_keys_aux(v) for v in json_value]
        elif isinstance(json_value, dict):
            return {conversion_table.get(k, k):map_keys_aux(v) for k,v in json_value.items()}
        else:
            return json_value

    return map_keys_aux(json_value)

Функция фокусируется на словарных ключах: conversion_table.get(k, k) равно conversion_table[k], если ключ присутствует в таблице преобразования, или сам ключ в противном случае.

>>> j1toj2 = {"field_5":"id", "field_12":"email", "field_20":"name_primary", "field_28":"assign", "field_44":"hr_id"}
>>> mapped_j1 = map_keys(j1, j1toj2)

Теперь код чище, и вывод может быть более полезным для PUT:

>>> d1 = {record["id"]:record for record in mapped_j1["records"]}
>>> present_in_j2 = set(record["id"] for record in j2["records"])
>>> {"records":[record for record in mapped_j1["records"] if record["id"] in present_in_j2]}
{'records': [{'id': 2329309831, 'email': {'email': 'mherbitz345@test.com'}, 'name_primary': {'last': 'Herbitz', 'first': 'Michael'}, 'assign': ['9002329309831', '9002329309112', '8002329309999'], 'hr_id': ['1002329309832']}]}
0 голосов
/ 12 ноября 2018

Если вы прочитаете json, он выведет dict. Вы ищете конкретный ключ в списке значений.

if 'records' in j2:
  r = j2['records'][0].get('id', []) # defaults if id does not exist

Это лучше сделать рекурсивный поиск, но я не знаю, как организованы ваши данные, чтобы быстро найти решение.

Чтобы дать представление о рекурсивном поиске, рассмотрим этот пример

def resursiveSearch(dictionary, target):
    if target in dictionary:
        return dictionary[target]
    for key, value in dictionary.items():
        if isinstance(value, dict):
            target = resursiveSearch(value, target)
            if target:
                return target


a = {'test' : 'b', 'test1' : dict(x = dict(z = 3), y = 2)}

print(resursiveSearch(a, 'z'))
...