Преобразование всех списков в dict в dict, рассматривая индекс списка как ключ в python - PullRequest
1 голос
/ 21 марта 2019

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

Пример ввода :

{
    "checksum": "c540fcd985bf88c87e48c2bfa1df5498",
    "data": {
        "sampleMetrics": {
            "name": "DNA Library QC Metrics",
            "passQualityControl": true,
            "metrics": [{
                "name": "CONTAMINATION_SCORE",
                "value": 1302,
                "LSL": 0,
                "USL": 3106,
                "UOM": "NA"
            }]
        }
    }
}

Ожидаемый результат :

{
    "checksum": "c540fcd985bf88c87e48c2bfa1df5498",
    "data": {
        "sampleMetrics": {
            "name": "DNA Library QC Metrics",
            "passQualityControl": true,
            "metrics": {
                "0": {
                    "name": "CONTAMINATION_SCORE"
                },
                "1": {
                    "value": 1302
                },
                "2": {
                    "LSL": 0
                },
                "3": {
                    "USL": 3106
                },
                "4": {
                    "UOM": "NA"
                }
            }
        }
    }
}

Пробная версия :

def list_to_dict_by_index(lst):
    print  {str(k): str(v) for k, v in enumerate(lst)}

list_to_dict_by_index([ {"d1" : 1}, {"d2" : 2} ])

Но это работает для простого списка. Как я могу сделать то же самое для всех списков в dict?

(Независимо от того, где список есть в dict.)

Список может содержать другой список :

например: образец ввода2 :

"metrics": [{
    "name": ["CONTAMINATION_SCORE", "TOTAL_SCORE"],
    "value": 1302,
    "LSL": 0,
    "USL": 3106,
    "UOM": "NA"
}]

образец вывода2 :

"metrics" : {
    "0": {
        "name": {
            "0": "CONTAMINATION_SCORE",
            "1": "TOTAL_SCORE"
        }
    },
    "1": {
        "value": 1302
    },
    "2": {
        "LSL": 0
    },
    "3": {
        "USL": 3106
    },
    "4": {
        "UOM": "NA"
    }
}

Ответы [ 3 ]

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

Ваш второй пример ввода / вывода содержит компоненты, которые соответствуют заголовку вопроса, а именно преобразование списков в словари с индексами списков в качестве ключей:

# input
"name": ["CONTAMINATION_SCORE", "TOTAL_SCORE"]

# output
"name": {
    "0": "CONTAMINATION_SCORE",
    "1": "TOTAL_SCORE"
}

Однако оба примера ввода / вывода содержат списки словарей, которые, как ожидается, будут преобразованы по-разному, то есть в словарь словарей с ключами в качестве перечислимых индексов записей словаря.

# input
"metrics": [{
    ...
    "USL": 3106,
    "UOM": "NA"
}]

# output
"metrics" : {
    ...
    "3": {
        "USL": 3106
    },
    "4": {
        "UOM": "NA"
    }
}

Это много слов, которые пытаются сформулировать по существу следующие два случая:

  1. {[{'foo': 'bar'}]} => {'0': {'foo': 'bar'}}
  2. {'foo': ['bar']} => {'foo': {'0': 'bar'}}

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

from collections import abv
def update(d):
    for k, v in d.copy().items():
        if isinstance(v, abc.Mapping):
            d[k] = update(v)
        else:
            d[k] = iv
    return d

Используйте iteritems вместо элементов, если вы используете python 2, а не python 3. Кроме того, необходимо копировать, чтобы итератор не был аннулирован при изменении словаря.

Вы можете работать в перечислительном цикле, как вы изначально использовали для получения рабочего решения. Осторожно добавлять рекурсивные вызовы, чтобы повлиять на все уровни словаря. В совокупности это может выглядеть примерно так:

from collections import abc

def list_of_dict_to_dict(d):
    dd = {}
    for i, (key, val) in enumerate(d.copy().items()):
        dd[i] = {}
        if isinstance(val, abc.Mapping):
            dd[i][key] = transform_dict(val)
        elif isinstance(val, list):
            dd[i][key] = list_to_dict(val)
        else:
            dd[i][key] = val
    return dd

def list_to_dict(l):
    d = {}
    for i, val in enumerate(l):
        if isinstance(val, abc.Mapping):
            d[i] = transform_dict(val)
        else:
            d[i] = val
    return d

def transform_dict(d):
    for k, v in d.copy().items():
        if isinstance(v, list):
            if isinstance(v[0], abc.Mapping) and len(v) == 1:
                d[k] = list_of_dict_to_dict(v[0])
            else:
                d[k] = list_to_dict(v)
        elif isinstance(v, abc.Mapping):
            d[k] = transform_dict(v)
        else:
            d[k] = v
    return d

Предполагается, что список словарей всегда содержит один словарь. Не ясно, что вы ожидаете в других случаях.

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

То, что вы спрашиваете, понятно, но ваш первый пример не соответствует правилу «Преобразование всех списков в dict в dict с учетом индекса списка в качестве ключа». Ключ metrics отображается в список с одним элементом, и этот элемент является словарем: [{...}]. Следовательно, ваш ожидаемый результат:

...
        "metrics": {
            "0": {
                "name": "CONTAMINATION_SCORE",
                "value": 1302,
                "LSL": 0,
                "USL": 3106,
                "UOM": "NA"
            }
        }
...

Если это то, что вы хотите, вам просто нужно использовать DFS :

def list_to_dict_by_key(json_value):
    if isinstance(json_value, list):
        return {str(i):list_to_dict_by_key(v) for i,v in enumerate(json_value)}
    elif isinstance(json_value, dict):
        return {k:list_to_dict_by_key(v) for k,v in json_value.items()}
    else:
        return json_value

Списки заменены словарями. Значения словарей обрабатываются.

>>> list_to_dict_by_key(sample1)
{'checksum': 'c540fcd985bf88c87e48c2bfa1df5498', 'data': {'sampleMetrics': {'name': 'DNA Library QC Metrics', 'passQualityControl': True, 'metrics': {'0': {'name': 'CONTAMINATION_SCORE', 'value': 1302, 'LSL': 0, 'USL': 3106, 'UOM': 'NA'}}}}}
>>> list_to_dict_by_key(sample2)
{'checksum': 'c540fcd985bf88c87e48c2bfa1df5498', 'data': {'sampleMetrics': {'name': 'DNA Library QC Metrics', 'passQualityControl': True, 'metrics': {'0': {'name': {'0': 'CONTAMINATION_SCORE', '1': 'TOTAL_SCORE'}, 'value': 1302, 'LSL': 0, 'USL': 3106, 'UOM': 'NA'}}}}}

РЕДАКТИРОВАТЬ : sample1 ваш первый Пример ввода , а sample2 почти то же самое: "name": ["CONTAMINATION_SCORE", "TOTAL_SCORE"] заменяет "name": "CONTAMINATION_SCORE"

0 голосов
/ 21 марта 2019
dic = {
    "checksum": "c540fcd985bf88c87e48c2bfa1df5498",
    "data": {
        "sampleMetrics": {
            "name": "DNA Library QC Metrics",
            "passQualityControl": True,
            "metrics": [{
                "name": "CONTAMINATION_SCORE",
                "value": 1302,
                "LSL": 0,
                "USL": 3106,
                "UOM": "NA"
            }]
        }
    }
}

dic2 = dic['data']['sampleMetrics']['metrics']
dic3 ={}
for i in dic2:
    for index,  j in enumerate(i,0):
        dic3[index]={j:i[j]}

dic['data']['sampleMetrics']['metrics'] = dic3

print(dic)

"""
output 
{
  'checksum': 'c540fcd985bf88c87e48c2bfa1df5498', 
  'data': {
           'sampleMetrics': {
                  'name': 'DNA Library QC Metrics',
                  'passQualityControl': True,
                  'metrics': {
                        0: {
                              'name': 'CONTAMINATION_SCORE'
                            },
                        1: {
                            'value': 1302
                            }, 
                        2: { 
                                'LSL': 0
                           },
                        3: {
                            'USL': 3106
                           },
                        4: {
                              'UOM': 'NA'
                            }
                            }
                           }
        }
}
"""
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...