如何在与现有记录集成时使用递归嵌套字典
how to use recursion to nest dictionaries while integrating with existing records
我正在将 Open Street Map 中的一些 XML 数据解析为 JSON(稍后将上传到数据库)。它很大,所以我正在使用 iterparse。我有一些标签看起来像这样
<tag 'k'=stringA:stringB:stringC 'v'=value>
我想解析成
{stringA: {stringB: {stringC: value} } }
我已经用丑陋的硬编码做到了。但是,我想创建一个使用递归来解决相同问题的函数,以防 'k' 属性值包含任意多个 ':'.
我创造了这个
def nestify(l):
"""Takes a list l and returns nested dictionaries where each element from
the list is both a key to the inner dictionary and a value to the outer,
except for the last element of the list, one which is only a value.
For best understanding, feed w = [ 'a', 'b', 'c', 'd', 'e', 'f', 'v'] to the
function and look at the output."""
n = len(l)
if n==2:
key = l[0]
value = l[1]
else:
key = l[0]
value = nestify(l[1:])
return {key:value}
有效。 (您必须先将键和值放入列表中。)但不是真的,因为它总是会创建一个新字典。我需要它尊重以前的数据并进行整合。例如,如果我的解析器遇到
<tag 'k'=a:b:c 'v'=1 />
然后在同一个元素中
<tag 'k'=a:d:e 'v'=2 />
我需要它来制作
{a: {'b': {'c' : 1}, 'd' : {'e' : 2}}}
而不是
{a: {'b' : {'c' : 1}}}
{a: {'d' : {'e' : 2}}}
我试过这个代码:
def smart_nestify(l, record):
n = len(l)
if n==2:
key = l[0]
value = l[1]
else:
key = l[0]
value = smart_nestify(l[1:], key)
if key not in record:
return {key:value}
else:
record[key] = value
return record
但它仍然会覆盖并且 returns 只会覆盖最新的记录。这是为什么?我该如何修复此代码?
有时只使用迭代比递归更好。这是迭代答案。
g_values = dict()
def make_nested(l):
"""
l is the array like you have for nestify
e.g., ['a', 'b', 'c', 1 ] or ['a', 'd', 'e', 2]
"""
global g_values
value = l[-1] ; l = l[:-1]
last_dict = None
for x in l[:-1]:
mp_temp = last_dict if last_dict is not None or g_values
last_dict = mp_temp.get(x)
if last_dict is None:
mp_temp[x] = dict()
last_dict = mp_temp[x]
last_dict[l[-1]] = value
虽然我没有测试,但你也可以递归地尝试这样的事情:
def make_nested(values, l):
if len(l == 2):
values[l[0]] = l[1]
return
mp = values.get(l[0])
if mp is None:
values[l[0]] = dict()
make_nested(values[l[0]], l[1:])
else:
make_nested(mp, l[1:])
这是一个 "smarter" nestify,它将列表 l
合并到字典 record
:
def smarter_nestify(l, record):
if len(l) == 2:
return {l[0]: l[1]}
key = l.pop(0)
record[key] = smarter_nestify(l, record.get(key, {}))
return record
每次通过递归,它从列表中弹出第一个元素 l.pop(0)
并合并字典下一级的值 record.get(key, {})
.
你可以像这样用两个列表来调用它:
l = ['a', 'b', 'c', 1]
record = smarter_nestify(l, {})
l = ['a', 'd', 'e', 2]
record = smarter_nestify(l, record)
print record
我正在将 Open Street Map 中的一些 XML 数据解析为 JSON(稍后将上传到数据库)。它很大,所以我正在使用 iterparse。我有一些标签看起来像这样
<tag 'k'=stringA:stringB:stringC 'v'=value>
我想解析成
{stringA: {stringB: {stringC: value} } }
我已经用丑陋的硬编码做到了。但是,我想创建一个使用递归来解决相同问题的函数,以防 'k' 属性值包含任意多个 ':'.
我创造了这个
def nestify(l):
"""Takes a list l and returns nested dictionaries where each element from
the list is both a key to the inner dictionary and a value to the outer,
except for the last element of the list, one which is only a value.
For best understanding, feed w = [ 'a', 'b', 'c', 'd', 'e', 'f', 'v'] to the
function and look at the output."""
n = len(l)
if n==2:
key = l[0]
value = l[1]
else:
key = l[0]
value = nestify(l[1:])
return {key:value}
有效。 (您必须先将键和值放入列表中。)但不是真的,因为它总是会创建一个新字典。我需要它尊重以前的数据并进行整合。例如,如果我的解析器遇到
<tag 'k'=a:b:c 'v'=1 />
然后在同一个元素中
<tag 'k'=a:d:e 'v'=2 />
我需要它来制作
{a: {'b': {'c' : 1}, 'd' : {'e' : 2}}}
而不是
{a: {'b' : {'c' : 1}}}
{a: {'d' : {'e' : 2}}}
我试过这个代码:
def smart_nestify(l, record):
n = len(l)
if n==2:
key = l[0]
value = l[1]
else:
key = l[0]
value = smart_nestify(l[1:], key)
if key not in record:
return {key:value}
else:
record[key] = value
return record
但它仍然会覆盖并且 returns 只会覆盖最新的记录。这是为什么?我该如何修复此代码?
有时只使用迭代比递归更好。这是迭代答案。
g_values = dict()
def make_nested(l):
"""
l is the array like you have for nestify
e.g., ['a', 'b', 'c', 1 ] or ['a', 'd', 'e', 2]
"""
global g_values
value = l[-1] ; l = l[:-1]
last_dict = None
for x in l[:-1]:
mp_temp = last_dict if last_dict is not None or g_values
last_dict = mp_temp.get(x)
if last_dict is None:
mp_temp[x] = dict()
last_dict = mp_temp[x]
last_dict[l[-1]] = value
虽然我没有测试,但你也可以递归地尝试这样的事情:
def make_nested(values, l):
if len(l == 2):
values[l[0]] = l[1]
return
mp = values.get(l[0])
if mp is None:
values[l[0]] = dict()
make_nested(values[l[0]], l[1:])
else:
make_nested(mp, l[1:])
这是一个 "smarter" nestify,它将列表 l
合并到字典 record
:
def smarter_nestify(l, record):
if len(l) == 2:
return {l[0]: l[1]}
key = l.pop(0)
record[key] = smarter_nestify(l, record.get(key, {}))
return record
每次通过递归,它从列表中弹出第一个元素 l.pop(0)
并合并字典下一级的值 record.get(key, {})
.
你可以像这样用两个列表来调用它:
l = ['a', 'b', 'c', 1]
record = smarter_nestify(l, {})
l = ['a', 'd', 'e', 2]
record = smarter_nestify(l, record)
print record