Удалить часть имени столбца после второй & ldquo; _ & rdquo; [Дубликат]

Вот семейство рекурсивных генераторов, которые можно использовать для поиска объекта, состоящего из диктов и списков. find_key дает кортеж, содержащий список ключей словаря и индексы списка, которые приводят к ключу, который вы передаете; кортеж также содержит значение, связанное с этим ключом.

def find_key(obj, key):
    if isinstance(obj, dict):
        yield from iter_dict(obj, key, [])
    elif isinstance(obj, list):
        yield from iter_list(obj, key, [])

def iter_dict(d, key, indices):
    for k, v in d.items():
        if k == key:
            yield indices + [k], v
        if isinstance(v, dict):
            yield from iter_dict(v, key, indices + [k])
        elif isinstance(v, list):
            yield from iter_list(v, key, indices + [k])

def iter_list(seq, key, indices):
    for k, v in enumerate(seq):
        if isinstance(v, dict):
            yield from iter_dict(v, key, indices + [k])
        elif isinstance(v, list):
            yield from iter_list(v, key, indices + [k])

# test

data = {
    '1_data': {
        '4_data': [
            {'5_data': 'hooray'},
            {'3_data': 'hooray2'}
        ], 
        '2_data': []
    }
}

for t in find_key(data, '3_data'):
    print(t)

output

(['1_data', '4_data', 1, '3_data'], 'hooray2')

Чтобы получить один ключ, если он является генератором, он найдет все соответствующие ключи. вы можете передать find_key в функцию next. И если вы хотите использовать список ключей для извлечения связанного значения, вы можете использовать простой цикл for.

seq, val = next(find_key(data, '3_data'))
print('seq:', seq, 'val:', val)

obj = data
for k in seq:
    obj = obj[k]
print('obj:', obj, obj == val)

output

seq: ['1_data', '4_data', 1, '3_data'] val: hooray2
obj: hooray2 True

Если ключ может быть отсутствует, затем дайте next соответствующий кортеж по умолчанию. Например:

seq, val = next(find_key(data, '6_data'), ([], None))
print('seq:', seq, 'val:', val)
if seq:
    obj = data
    for k in seq:
        obj = obj[k]
    print('obj:', obj, obj == val)

output

seq: [] val: None

Обратите внимание, что этот код предназначен для Python 3. Чтобы запустить его на Python 2, вам необходимо заменить все yield from например, заменить

yield from iter_dict(obj, key, [])

на

for u in iter_dict(obj, key, []):
    yield u

Как это работает

Чтобы понять, как работает этот код, вам нужно быть знакомым с рекурсия и с генераторами Python . Вы также можете найти эту страницу полезной: Понимание генераторов в Python ; существуют также различные обучающие программы для генераторов Python, доступные в Интернете.

Объект Python, возвращенный json.load или json.loads, обычно является dict, но также может быть списком. Мы передаем этот объект генератору find_key в качестве obj arg, а также строку key, которую хотим найти. find_key затем вызывает либо iter_dict, либо iter_list, в случае необходимости, передавая им объект, ключ и пустой список indices, который используется для сбора ключей dict и индексов списка, которые приводят к ключу, который мы want.

iter_dict выполняет итерацию по каждой (k, v) паре на верхнем уровне своего d dict arg. Если k соответствует клавише, которую мы ищем, то текущий indices список будет добавлен с добавленным к нему k вместе со связанным значением. Поскольку iter_dict рекурсивно, полученные пары (индексы список, значение) передаются до предыдущего уровня рекурсии, в конечном итоге доходя до find_key, а затем кода, который называется find_key. Обратите внимание, что это «базовый случай» нашей рекурсии: это часть кода, которая определяет, ведет ли этот путь рекурсии к нужному ключу. Если путь рекурсии никогда не находит ключ, соответствующий ключевому слову, который мы ищем, тогда этот путь рекурсии ничего не добавит к indices, и он завершится без каких-либо изменений.

Если текущий v является dict, тогда нам нужно изучить все пары (ключ, значение), которые он содержит. Мы делаем это путем рекурсивного вызова iter_dict, передавая, что v является его стартовым объектом и текущим indices списком. Если текущий v является списком, мы вместо этого вызываем iter_list, передавая ему одни и те же аргументы.

iter_list работает аналогично iter_dict, за исключением того, что в списке нет никаких ключей, это только содержит значения, поэтому мы не выполняем тест k == key, мы просто рекурсируем в любые dicts или списки, которые содержит исходный список.

Конечным результатом этого процесса является то, что когда мы перебираем find_key мы получаем пары (индексы, значение), где каждый список indices представляет собой последовательность ключей dict и индексов списка, которые успешно завершаются в элементе dict с помощью нашего желаемого ключа, а value - это значение, связанное с этим конкретным ключом .

Если вы хотите увидеть некоторые другие примеры использования этого кода, см. , как изменить ключ вложенных Json и . Как я могу выбрать глубоко вложенный ключ: значения из словаря в python .

1
задан Bruce Wayne 26 March 2019 в 19:00
поделиться