简体   繁体   English

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

[英]How to iterate over nested dictionary structure and operate on each string?

I have a dictionary that may contain any arbitrary order of strings, lists of strings or nested dictionaries that ultimate terminate in strings. 我有一本字典,其中可能包含任意任意顺序的字符串,字符串列表或最终以字符串结尾的嵌套字典。 I would like to iterate over this dictionary and perform an action on each string. 我想遍历该字典并对每个字符串执行一个操作。

This question is close to what I'm looking for but I was unsuccessful in applying that solution to my own. 这个问题与我要寻找的问题很接近,但是我未能将该解决方案应用于我自己的解决方案。

I need to apply the function os.path.expanduser() to each string in the following dictionary: 我需要将函数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'
    )
)

Ideally I would like to define a class that when called on a normal dictionary, will apply os.path.expanduser() on each string element of that dictionary. 理想情况下,我想定义一个在普通字典上调用时将在该字典的每个字符串元素上应用os.path.expanduser()

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

How can I achieve this? 我该如何实现?

This can be easily done with a recursive function. 这可以通过递归函数轻松完成。 Let's have a look at an example implementation. 让我们看一个示例实现。 Here we will map all the strings in the given container to a given function, we will also use List Comprehensions and Dictionary Comprehensions to mimic the original nested structure. 在这里,我们将给定容器中的所有字符串映射到给定函数,我们还将使用List ComprehensionsDictionary Comprehensions模仿原始的嵌套结构。 In addition, isinstance built in function is used to check the type of a given parameter: 另外,内置的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]

Applies func to every string in the container. func应用于容器中的每个字符串。 Test it with your example dictionary and os.path.expanduser : 使用示例字典和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)

And sure enough you get the desired output: 并且确实可以得到所需的输出:

{'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'}}

Here's a function that takes a nested structure x as input, and return a similarly nested structure where all strings have been expanded: 这是一个函数,它将嵌套结构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

So eg calling it with 因此,例如用

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

will return 将返回

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

Here's a function that will do it: 这是一个可以实现的功能:

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))

Output: 输出:

{
    "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"
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM