Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/python-3.x/16.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python “我怎么能?”;壁球“;字典清单?_Python_Python 3.x_Data Structures_Django Auditlog - Fatal编程技术网

Python “我怎么能?”;壁球“;字典清单?

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': [

很抱歉标题不清楚,但我不知道如何描述我正在尝试的操作

django auditlog在django模型中生成跟踪字段的“差异”,其格式为
{'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
我不知道你可以分配设置默认值的步骤