【问题标题】:Converting all lists in dict to dict by considering list index as key in python通过将列表索引视为python中的键将dict中的所有列表转换为dict
【发布时间】:2019-08-11 23:08:24
【问题描述】:

我正在尝试通过将列表索引视为其键来转换 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 中的所有列表执行相同操作?

(无论字典中的列表在哪里。)

列表可能包含另一个列表:

例如: 样本输入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"
    }
}

【问题讨论】:

  • 作为一个想法,我建议您查看“dict deep merge”问题和答案:stackoverflow.com/questions/20656135/… 看起来您需要更改几行才能获得所需的内容。如果有任何问题,我可以更详细地描述更改。
  • 我不想合并字典。我只想通过将列表索引视为键来转换 dict 中的所有列表。
  • 好的。那只是一个正确解决方案的想法。因此,如果您以该答案为基础,请添加 elif isinstance(value, list): 并将您的代码放入其中,然后您将获得解决方案。我应该更详细地描述我的想法并使用更多代码示例吗?
  • @FedorDikarev :我已经尝试过isinstance(value, list)。但无法以预期的方式进入

标签: python python-3.x python-2.7 list dictionary


【解决方案1】:
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'
                            }
                            }
                           }
        }
}
"""

【讨论】:

  • dic['data']['sampleMetrics']['metrics'] 只是有问题的例子。列表可能出现在任何关键的地方(/父键)可能是任何东西。
  • @HarshaBiyani 那么你需要检查它是否是 list ,如果 list 然后检查它里面是否是 dict 。如果 dict 那么就使用我在这里做的方法
  • 是的,我知道这个简单的答案。我也用递归函数试过这个。但未能成功。
  • 最好提供完整的输入数据并相应地提出问题并构建 json,使其始终遵循相同的结构
  • Converting all lists in dict to dict by considering list index as key in python 。这是我的问题。如果您再次阅读问题,您将得到我想要实现的目标。
【解决方案2】:

您的第二个示例输入/输出包含与问题标题一致的组件,即将列表转换为以列表索引为键的字典:

# 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

如果您使用的是 python 2 而不是 python 3,请使用 iteritems 而不是项目。此外,复制是必要的,以便在字典发生变异时迭代器不会失效。

您可以像最初用来获得有效解决方案一样在枚举循环中工作。小心添加递归调用以影响字典的所有级别。总的来说,这可能类似于以下内容:

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

这假设字典列表总是包含一个字典。不清楚您在其他情况下的期望。

【讨论】:

  • 这给了我与输入相同的输出。
  • 确实如此。照原样,此代码无法完成您想要的。它是可以从答案中的提示中得出的解决方案的基础。
  • 我知道isinstance。我已经尝试过if isinstance(v, list) 但没有运气
  • 您肯定需要使用if is instance(v, list) 来确定每个条目是否是一个列表,以便您可以采取适当的措施。我贴的代码会遍历字典,这是一个开始。
  • @HarshaBiyani 添加了工作代码,虽然它并不漂亮。
【解决方案3】:

您的要求很清楚,但您的第一个示例与“通过将列表索引视为键将 dict 中的所有列表转换为 dict”的规则不匹配。 metrics 键映射到具有 one 元素的列表,该元素是一个字典:[{...}]。因此,您的预期输出是:

...
        "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"

【讨论】:

  • 我希望输出为您正在使用的输入。输入将是列表。
  • @HarshaBiyani 你能详细说明一下吗?我的输入中有列表。对于每个列表[a, b, c],输出为{"0":a, "1":b, "2":c}(根据要求)。如果列表只有一个元素:[a],则输出为{"0":a}。
猜你喜欢
  • 1970-01-01
  • 2018-10-14
  • 1970-01-01
  • 1970-01-01
  • 2017-08-25
  • 2021-10-10
  • 1970-01-01
  • 1970-01-01
  • 2016-12-02
相关资源
最近更新 更多