Python “我怎么能?”;壁球“;字典清单?
很抱歉标题不清楚,但我不知道如何描述我正在尝试的操作 django auditlog在django模型中生成跟踪字段的“差异”,其格式为Python “我怎么能?”;壁球“;字典清单?,python,python-3.x,data-structures,django-auditlog,Python,Python 3.x,Data Structures,Django Auditlog,很抱歉标题不清楚,但我不知道如何描述我正在尝试的操作 django auditlog在django模型中生成跟踪字段的“差异”,其格式为{'field_name':[old_value,new_value]},在字段更改时跟踪数据库中的字段。因此,我的数据库中特定行上的这些差异列表(首先按最新的差异排序)可能如下所示: # 1 [ { 'price': [490, 530] }, { 'status': [7, 1], }, { 'status': [
{'field_name':[old_value,new_value]}
,在字段更改时跟踪数据库中的字段。因此,我的数据库中特定行上的这些差异列表(首先按最新的差异排序)可能如下所示:
# 1
[
{
'price': [490, 530]
},
{
'status': [7, 1],
},
{
'status': [1, 7],
},
{
'status': [10, 1],
'price': [0, 490],
'location': [None, 'Calgary']
}
]
In [7]: print(squashed)
{'status': [10, 1], 'location': [None, 'Calgary'], 'price': [0, 530]}
我想像在Git中一样“挤压”这个历史:获取字段的第一个值和字段的最新值,然后删除所有中间值。因此,在上面的示例中,我想要以下输出:
# 2
{
'price': [0, 530],
'status': [10, 1],
'location': [None, 'Calgary']
}
请注意,多个'status'
和'price'
更改已压缩为一对旧/新的更改
我相信我可以通过首先创建一个中间字典来实现这一点,在这个字典中,所有的更改都连接在一起:
# 3
{
'price': [[0, 490], [490, 530]],
'status': [[10, 1], [1, 7], [7, 1]],
'location': [[None, 'Calgary']]
}
然后提取每个字典元素的第一个列表元素的第一个列表元素,以及每个字典元素的最后一个列表元素的最后一个列表元素
什么是使
#1
看起来像#3
的干净的python方法?在所示的示例数据中,更改按相反的时间顺序列出。只需在列表中逐步建立一组合并字段:每个重复的字段更新“旧”值,而“新”值来自第一次更改
changes = [
{
'price': [490, 530]
},
{
'status': [7, 1],
},
{
'status': [1, 7],
},
{
'status': [10, 1],
'price': [0, 490],
'location': [None, 'Calgary']
}
]
squashed = {}
for delta in changes:
for field, values in delta.items():
if field in squashed:
squashed[field][0] = values[0]
else:
squashed[field] = values
结果如下:
# 1
[
{
'price': [490, 530]
},
{
'status': [7, 1],
},
{
'status': [1, 7],
},
{
'status': [10, 1],
'price': [0, 490],
'location': [None, 'Calgary']
}
]
In [7]: print(squashed)
{'status': [10, 1], 'location': [None, 'Calgary'], 'price': [0, 530]}
在所示的示例数据中,更改按相反的时间顺序列出。只需在列表中逐步建立一组合并字段:每个重复的字段更新“旧”值,而“新”值来自第一次更改
changes = [
{
'price': [490, 530]
},
{
'status': [7, 1],
},
{
'status': [1, 7],
},
{
'status': [10, 1],
'price': [0, 490],
'location': [None, 'Calgary']
}
]
squashed = {}
for delta in changes:
for field, values in delta.items():
if field in squashed:
squashed[field][0] = values[0]
else:
squashed[field] = values
结果如下:
# 1
[
{
'price': [490, 530]
},
{
'status': [7, 1],
},
{
'status': [1, 7],
},
{
'status': [10, 1],
'price': [0, 490],
'location': [None, 'Calgary']
}
]
In [7]: print(squashed)
{'status': [10, 1], 'location': [None, 'Calgary'], 'price': [0, 530]}
你可以直接去2号。在#1上迭代时,如果键是新的,则创建一个新条目,并只更新结束状态:
l = [
{
'price': [490, 530]
},
{
'status': [7, 1],
},
{
'status': [1, 7],
},
{
'status': [10, 1],
'price': [0, 490],
'location': [None, 'Calgary']
}
]
l.reverse()
squashed = {}
for x in l:
for k,v in x.items():
squashed.setdefault(k, [v[0],v[1]])
squashed[k][1] = v[1]
print squashed
你可以直接去2号。在#1上迭代时,如果键是新的,则创建一个新条目,并只更新结束状态:
l = [
{
'price': [490, 530]
},
{
'status': [7, 1],
},
{
'status': [1, 7],
},
{
'status': [10, 1],
'price': [0, 490],
'location': [None, 'Calgary']
}
]
l.reverse()
squashed = {}
for x in l:
for k,v in x.items():
squashed.setdefault(k, [v[0],v[1]])
squashed[k][1] = v[1]
print squashed
dict.setdefault()
可能对您有用:
from pprint import pprint
one = [
{
'price': [490, 530]
},
{
'status': [7, 1],
},
{
'status': [1, 7],
},
{
'status': [10, 1],
'price': [0, 490],
'location': [None, 'Calgary']
}
]
two = {}
for d in one:
for k,v in d.items():
two.setdefault(k, v)[0] = v[0]
pprint(two)
结果:
{'location': [None, 'Calgary'], 'price': [0, 530], 'status': [10, 1]}
dict.setdefault()
可能对您有用:
from pprint import pprint
one = [
{
'price': [490, 530]
},
{
'status': [7, 1],
},
{
'status': [1, 7],
},
{
'status': [10, 1],
'price': [0, 490],
'location': [None, 'Calgary']
}
]
two = {}
for d in one:
for k,v in d.items():
two.setdefault(k, v)[0] = v[0]
pprint(two)
结果:
{'location': [None, 'Calgary'], 'price': [0, 530], 'status': [10, 1]}
考虑到更新列表:
crunch=lambda d,u: dict(d.items()+[(k, [u[k][0], d.get(k, u[k])[1]]) for k in u])
reduce(crunch, l)
这给了你:
{'location': [None, 'Calgary'], 'price': [0, 530], 'status': [10, 1]}
因此,reduce函数的第一个参数是一个函数,它通过以下方式接收从列表中获取的一对参数:
l = [ 0, 1, 2, 3 ]
reduce( f, l ) == f( f ( f( f(0, 1), 2), 3)
通过这种方式,lambda函数接收一个增量构建的字典作为第一个参数(d),并通过迭代u中的更新来构建一个新的更新字典
lambda函数变得过于复杂,因为update方法不返回字典,而不返回任何字典,因此它正在构建一个新的字典,只是为了能够返回它
您可以将lambda替换为实际函数,这是一个更清晰的选择,可以轻松返回更新的字典:
def crunch(dic, updates):
dic.update(
{ k: [updates[k][0], dic.get(k, updates[k])[1]] for k in updates }
)
return dic # gonna be the input of the next iteration
然后做:
reduce(crunch, l)
如果k存在,dictionary的get方法将返回item值,如果k不存在,则将第二个参数作为默认值返回,因此它不需要defaultdict或setdefault 考虑更新列表:
crunch=lambda d,u: dict(d.items()+[(k, [u[k][0], d.get(k, u[k])[1]]) for k in u])
reduce(crunch, l)
这给了你:
{'location': [None, 'Calgary'], 'price': [0, 530], 'status': [10, 1]}
因此,reduce函数的第一个参数是一个函数,它通过以下方式接收从列表中获取的一对参数:
l = [ 0, 1, 2, 3 ]
reduce( f, l ) == f( f ( f( f(0, 1), 2), 3)
通过这种方式,lambda函数接收一个增量构建的字典作为第一个参数(d),并通过迭代u中的更新来构建一个新的更新字典
lambda函数变得过于复杂,因为update方法不返回字典,而不返回任何字典,因此它正在构建一个新的字典,只是为了能够返回它
您可以将lambda替换为实际函数,这是一个更清晰的选择,可以轻松返回更新的字典:
def crunch(dic, updates):
dic.update(
{ k: [updates[k][0], dic.get(k, updates[k])[1]] for k in updates }
)
return dic # gonna be the input of the next iteration
然后做:
reduce(crunch, l)
如果k存在,dictionary的get方法将返回item值,如果k不存在,则将第二个参数作为默认值返回,因此它不需要defaultdict或setdefault #2与文本描述相矛盾。
'price':[None,530]
是如何产生的?@PadraicCunningham typo,edited@KarolyHorvath打字错误edited@PadraicCunningham这是倒序的。”“价格”从0到490,然后从490到530,最终结果为[0530]#2与文本描述相矛盾。“价格”:[None,530]
是如何产生的?@padraickenningham typo,edited@KarolyHorvath打字错误edited@PadraicCunningham这是倒序的。”“价格”从0上升到490,然后从490上升到530,最终结果为[0530],多亏了一个有趣的替代方案,但一些解释可能会更好。我发布了最低价格,以便逐步改进。你不觉得这有点让那些试图帮助你找到正确答案的人失望吗?密集的一行是没有帮助的,除非你把它们拆开。对于>1k代表,您应该知道是的,我知道,因此我添加了更多信息,如您所见。如果你是2K以上的代表,我认为你应该少一点傲慢,慢一点投票。谢谢你澄清感谢一个有趣的替代方案,但一些解释会更好。我发布了最低限度,以逐步改进它。你不觉得这有点让那些试图帮助你找到正确答案的人失望吗?密集的一行是没有帮助的,除非你把它们拆开。对于>1k代表,您应该知道是的,我知道,因此我添加了更多信息,如您所见。谢谢你澄清我喜欢你如何重复使用最新的dict以避免更改列表我喜欢你如何重复使用最新的dict以避免更改列表我不知道你可以分配到setdefault
我不知道你可以分配设置默认值的步骤