Разделить список строк на словарные ключи в python - PullRequest
0 голосов
/ 30 января 2020

У меня есть строка 'request.context.user_id', и я хочу разделить строку на '.' и использовать каждый элемент в списке в качестве словарного ключа. Есть ли способ сделать это для списков различной длины, не пытаясь жестко закодировать все возможные длины списков после разделения?

parts = string.split('.')
if len(parts)==1:
    data = [x for x in logData if x[parts[0]] in listX]
elif len(parts)==2:
    data = [x for x in logData if x[parts[0]][parts[1]] in listX]
else:
    print("Add more hard code")

listX - это список строковых значений, которые должны быть получены с помощью x [ parts [0]] [parts [1] logData - это список, полученный при чтении файла json, и затем этот список можно прочитать в кадре данных, используя json_normalize ... часть df предоставлена, чтобы дать некоторый контекст о его структуре. список диктовок:

import json
from pandas.io.json import json_normalize

with open(project_root+"filename") as f:
    logData = json.load(f)

df = json_normalize(logData)

Ответы [ 2 ]

0 голосов
/ 31 января 2020

Если вы хотите произвольный подсчет, это означает, что вам нужно al oop. Вы можете использовать get несколько раз для детализации слоев словарей.

parts = "request.context.user_id".split(".")
logData = [{"request": {"context": {"user_id": "jim"}}}]
listX = "jim"

def generate(logData, parts):
    for x in logData:
        ref = x
        # ref will be, successively, x, then the 'request' dictionary, then the
        # 'context' dictionary, then the 'user_id' value 'jim'. 
        for key in parts:
            ref = ref[key]
        if ref in listX:
            yield x


data = list(generate(logData, parts)))  # ['jim']
0 голосов
/ 30 января 2020

Я только что понял в комментариях, которые вы сказали, что вы не хотите создавать новый словарь, а хотите получить доступ к существующему x через цепочку частей в списке.

(3.b) используйте for loop, чтобы получить / установить значение в ключе путь

В случае, если вы хотите прочитать значение только в конце пути в

import copy

def get_val(key_list, dict_):
    reduced = copy.deepcopy(dict_)
    for i in range(len(key_list)):
        reduced = reduced[key_list[i]]
    return reduced

# this solution isn't mine, see the link below
def set_val(dict_, key_list, value_):
    for key in key_list[:-1]:
        dict_ = dict_.setdefault(key, {})
    dict_[key_list[-1]] = value_
  • get_val() Где список ключей - это результат string.slit('.'), а dict_ - это словарь x в вашем случае. Вы можете пропустить часть copy.deepcopy(), это просто для параноидальных писков, как я - причина в том, что диктат python не является неизменным , таким образом, работает над глубокой копией (отдельным но точная копия в памяти) является решением.
  • set_val() Как я уже сказал, это не моя идея, кредит на @ Bakuriu
    dict.setdefault(key, default_value) позаботится о существующие ключи в x.

(3) оценка строки как кода с eval() и / или exec()

Итак, вот некрасивое небезопасное решение:

def chainer(key_list):
    new_str = ''
    for key in key_list:
        new_str = "{}['{}']".format(new_str, key)
    return new_str

x = {'request': {'context': {'user_id': 'is this what you are looking for?'}}}
keys = 'request.context.user_id'.split('.')
chained_keys = chainer(keys)

# quite dirty but you may use eval() to evaluate a string
print( eval("x{}".format(chained_keys)) )

# will print
is this what you are looking for?

, который является самым внутренним значением макета x dict

Я предполагаю, что вы можете использовать это в своем коде, как это

data = [x for x in logData if eval("x{}".format(chained_keys)) in listX]
# or in python 3.x with f-string
data = [x for x in logData if eval(f"x{chained_keys}") in listX]

. ..или что-то похожее.

Аналогично, вы можете использовать exec() для выполнения строки как кода, если хотите записать в x, хотя это так же грязно и небезопасно.

exec("x{} = '...or this, maybe?'".format(chained_keys))
print(x)

# will print
{'request': {'context': {'user_id': '...or this, maybe?'}}}

(2) Фактическое решение может быть recursive function следующим образом:

def nester(key_list):
    if len(key_list) == 0:
        return 'value'   # can change this to whatever you like
    else:
        return {key_list.pop(0): nester(key_list)}

keys = 'request.context.user_id'.split('.')  
# ['request', 'context', 'user_id']

data = nester(keys)
print(data)

# will result
{'request': {'context': {'user_id': 'value'}}}

(1) Решение с list comprehension для разделить строку на '.' и использовать каждый элемент в списке в качестве словарного ключа

data = {}
parts = 'request.context.user_id'.split('.')

if parts:   # one or more items
    [data.update({part: 'value'}) for part in parts]

print(data)

# the result
{'request': 'value', 'context': 'value', 'user_id': 'value'}

Вы можете перезаписать значения в data впоследствии.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...