如何遍历嵌套字典结构并对每个字符串进行操作?

时间:2018-11-12 07:19:46

标签: python dictionary

我有一个字典,其中可能包含任意任意顺序的字符串,字符串列表或最终以字符串结尾的嵌套字典。我想遍历该字典并对每个字符串执行一个操作。

This问题与我要寻找的问题很接近,但是我未能将该解决方案应用于自己的解决方案。

我需要将函数os.path.expanduser()应用于以下字典中的每个字符串:

x = dict(
    dir = dict(
        wd = '~/Desktop/WD',
        pymodule = [
            '~/Documents/PythonModule',
            '/Users/Username/Documents/PythonModule2'
        ],
        album = '~/Desktop/Album'
    ),
    file = dict(
        XML = '~/Downloads/data.xml',
        CSV = '~/Downloads/data.csv'
    )
)

理想情况下,我想定义一个类,当在普通词典中调用该类时,它将在该词典的每个字符串元素上应用os.path.expanduser()

class MyDict:
    def __init__(d):
        self.d = d
        # some operation to apply os.path.expanduser() on each string element of 'd'

我该如何实现?

3 个答案:

答案 0 :(得分:2)

这可以通过递归函数轻松完成。让我们看一个示例实现。在这里,我们将给定容器中的所有字符串映射到给定函数,我们还将使用List ComprehensionsDictionary Comprehensions来模仿原始的嵌套结构。另外,内置的isinstance函数用于检查给定参数的类型:

def convert(func, d):
  if (isinstance(d, str)):
    return func(d)
  elif (isinstance(d, dict)):
    return {key : convert(func, d[key]) for key in d}
  elif (isinstance(d, list)):
    return [convert(func, val) for val in d]

func应用于容器中的每个字符串。使用示例字典和os.path.expanduser对其进行测试:

x = dict(
    dir = dict(
        wd = '~/Desktop/WD',
        pymodule = [
            '~/Documents/PythonModule',
            '/Users/Username/Documents/PythonModule2'
        ],
        album = '~/Desktop/Album'
    ),
    file = dict(
        XML = '~/Downloads/data.xml',
        CSV = '~/Downloads/data.csv'
    )
)


import os
x = convert(os.path.expanduser, x)
print(x)

当然可以确保获得所需的输出:

{'dir': {'wd': '/home/runner/Desktop/WD', 'pymodule': ['/home/runner/Documents/PythonModule', '/Users/Username/Documents/PythonModule2'], 'album': '/home/runner/Desktop/Album'}, 'file': {'XML': '/home/runner/Downloads/data.xml', 'CSV': '/home/runner/Downloads/data.csv'}}

答案 1 :(得分:2)

这是一个函数,它使用一个嵌套结构x作为输入,并返回一个类似的嵌套结构,其中所有字符串都已扩展:

def expand(x):
    if isinstance(x, str):
        return os.path.expanduser(x)
    if isinstance(x, dict):
        return { key : expand(x[key]) for key in x }
    if isinstance(x, list):
        return [ expand(elem) for elem in x ]
    return x

例如用

调用
expand({1: '~/Hello', 2: ['~/World', '~/foo']})

将返回

{1: '/home/hkoehler/Hello', 2: ['/home/hkoehler/World', '/home/hkoehler/foo']}

答案 2 :(得分:0)

这里有个函数可以做到:

import json
import os

x = dict(
    dir = dict(
        wd = '~/Desktop/WD',
        pymodule = [
            '~/Documents/PythonModule',
            '/Users/Username/Documents/PythonModule2'
        ],
        album = '~/Desktop/Album'
    ),
    file = dict(
        XML = '~/Downloads/data.xml',
        CSV = '~/Downloads/data.csv'
    )
)

def func(d):
    for key, value in d.items():
        if isinstance(value, dict):
            func(value)
        elif isinstance(value, str):
            d[key] = os.path.expanduser(value)
        elif isinstance(value, list):
            for i, element in enumerate(value):
                if isinstance(element, str):
                    value[i] = os.path.expanduser(element)

func(x)
print(json.dumps(x, indent=4))

输出:

{
    "dir": {
        "wd": "C:\\Users\\martineau/Desktop/WD",
        "pymodule": [
            "C:\\Users\\martineau/Documents/PythonModule",
            "/Users/Username/Documents/PythonModule2"
        ],
        "album": "C:\\Users\\martineau/Desktop/Album"
    },
    "file": {
        "XML": "C:\\Users\\martineau/Downloads/data.xml",
        "CSV": "C:\\Users\\martineau/Downloads/data.csv"
    }
}