如何解决基于 .properties 文件制作 Python 字典
我想将 .properties-file 的键和值解析为 Python 字典。 我正在解析的 .properties-file 使用以下语法(键和值是示例):
key1.subkey1.subsubkey1=value1
key1.subkey1.subsubkey2=value2
key1.subkey2=value3
key2=value4
所以每个值对应一个键,由一个或多个用句点划分的级别组成。 目标是创建一个 Python 字典,其中每个键都是一个包含其值和子键的字典。字典应该是可递归迭代的,所以每一层都应该遵循相同的结构。
前面的例子应该产生以下类型的字典:
'subKeys':
'key1':
'subKeys':
'subkey1':
'subKeys':
'subsubkey1':
'val': 'value1'
'subsubkey2':
'val': 'value2'
'subkey2':
'val': 'value3'
'key2':
'val': 'value4'
我在 python 中使用以下算法循环它:
def setKeyAndValue(storageDict,rowParts):
keyParts = rowParts[0].split('.')
if not keyParts[0] in outputDict:
storageDict[keyParts[0]] = {}
newObj = storageDict[keyParts[0]]
for i in range(len(keyParts)):
if i == len(keyParts)-1:
# Reached the end of the key,save value to dictionary
newObj["val"] = rowParts[1]
else :
# Not yet at the end of the key
if "subKeys" not in newObj:
newObj["subKeys"] = {}
if keyParts[i+1] not in newObj["subKeys"]:
newObj["subKeys"][keyParts[i+1]] = {}
newObj = newObj["subKeys"][keyParts[i+1]]
f = open("FILEPATH.properties","r")
outputDict = {}
outputDict["subKeys"] = {}
outputDictSubKeys = outputDict["subKeys"]
for row in f:
if not row.startswith('#') and not row.startswith('//'):
parts = row.split('=',1)
if len(parts)== 2:
setKeyAndValue(outputDictSubKeys,parts)
f.close()
生成的字典(outputDict)缺少两个键值对(key1.subkey1.subsubkey1=value1, key1.subkey1.subsubkey2=value2):
'subKeys':
'key1':
'subKeys':
'subkey2':
'val': 'value3'
'key2':
'val': 'value4'
我很确定问题出在以下一行:
newObj = newObj["subKeys"][keyParts[i+1]]
我用循环的每次迭代替换字典中的 newObj。
有没有办法调整这个现有的算法以使其工作,如果没有,我应该如何重新开始?效率不是问题,属性文件不是很大。
解决方法
一些观察:
解决方案
数据
现在假设我们有一个名为 data.properties
的文件,其结构如下
key1.subkey1.subsubkey1=value1
key1.subkey1.subsubkey2=value2
key1.subkey2=value3
key2=value4
代码
然后我们可以使用下面的代码
import functools
from collections import defaultdict
from pprint import pprint
if __name__ == '__main__':
node = lambda: defaultdict(node)
trie = node()
with open("data.properties",'r') as file:
for line in file.readlines():
key,value = line.strip().split('=')
functools.reduce(dict.__getitem__,key.split('.'),trie)
val = (functools.reduce(lambda d,key: d.get(key),key.split('.')[:-1],trie))
val[key.split('.')[-1]] = value
pprint(trie)
输出
生成以下输出
defaultdict(<function <lambda> at 0x000002054579EF70>,{'key1': defaultdict(<function <lambda> at 0x000002054579EF70>,{'subkey1': defaultdict(<function <lambda> at 0x000002054579EF70>,{'subsubkey1': 'value1','subsubkey2': 'value2'}),'subkey2': 'value3'}),'key2': 'value4'})
defaultdict
可以忽略的地方,只要键在字典中。如果要删除defaultdict
属性,可以使用这个函数
def defaultdict_to_dict(data):
""" Convert a nested defaultdict to a normal dictionary. """
if isinstance(data,defaultdict):
data = dict(data)
if isinstance(data,dict):
for k,v in data.items():
data[k] = defaultdict_to_dict(v)
return data
并使用 pprint(defaultdict_to_dict(trie))
调用它。
这将输出
{'key1': {'subkey1': {'subsubkey1': 'value1','subsubkey2': 'value2'},'subkey2': 'value3'},'key2': 'value4'}
说明
大部分魔法发生在以下两行
1)
functools.reduce(dict.__getitem__,trie)
2)
val = (functools.reduce(lambda d,trie))
在第一行中,我们为所有键创建了 Trie,所有值(叶子)都将是 defaultdict
。这意味着它可以扩展任意深度(拥有任意数量的子键)。
在第二行中,我们按照键遍历 Trie,直到最后一个键。以key1.subkey1.subsubkey1=value1
为例,这段代码将类似于
val = trie['key1']['subkey1']
其中下一行 (val[key.split('.')[-1]] = value
) 等于
trie['key1']['subkey1']['subsubkey1'] = 'value1'
,
我复制了您的函数并测试了您的代码并进行了一些更改。下面的代码工作正常。
def setKeyAndValue(storageDict,rowParts):
print rowParts
keyParts = rowParts[0].split('.')
if not keyParts[0] in storageDict.keys():
storageDict[keyParts[0]] = {}
newObj = storageDict[keyParts[0]]
for i in range(len(keyParts)):
if i == len(keyParts)-1:
# Reached the end of the key,save value to dictionary
newObj["val"] = rowParts[1]
else :
# Not yet at the end of the key
if "subKeys" not in newObj:
newObj["subKeys"] = {}
if keyParts[i+1] not in newObj["subKeys"]:
newObj["subKeys"][keyParts[i+1]] = {}
newObj = newObj["subKeys"][keyParts[i+1]]
def main():
input = [
'key1.subkey1.subsubkey1=value1','key1.subkey1.subsubkey2=value2','key1.subkey2=value3','key2=value4'
]
ans = {}
ans1 = {
'subKeys': ans
}
for row in input:
parts = row.split('=',1)
setKeyAndValue(ans,parts)
print ans1
main()
输出如下:
{'subKeys': {'key2': {'val': 'value4'},'key1': {'subKeys': {'subkey2': {'val': 'value3'},'subkey1': {'subKeys': {'subsubkey1': {'val': 'value1'},'subsubkey2': {'val': 'value2'}}}}}}}
用 OutputDict
替换您的 storageDict.keys()
变量并编写了一个示例主函数。尝试自己运行它,看看它是否适合您。
我认为您的 OutputDict 仅包含 subKeys
键,因此条件将始终为真,您将用空白字典替换之前添加的字典。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。