[英]Updating an ordered list of dicts from a new list of dicts (priority merge)
我目前面临着不得不从规范的更改源半定期更新(同步)一个大的dicts列表,同时保持我自己的更新。 非标准合并,最简单的描述可能是: -
A
是我自己的dicts列表(由我的程序更新,包括缓存值作为附加键。 b
是从源头定期发送的信息(A最初与b相同)。 它包含几个键,但不是我添加到A的缓存值。 keys = ['key1', 'key2']
是A和b都有的键列表(A有更多的键。 mkey = 'mtime'
是A和b都有的特殊键,表示我应该使A的缓存值无效。 基本上,如果A
中的词典与b
中的词典匹配,我应该将词典保留在A中,除非b['mtime'] > A['mtime']
。 如果一个字典出现在A
而不是b
我摆脱它,而如果它出现在b
而不是A
我将它添加到A
。
我圣杯的目标是在不丢失任何缓存键值对A
不惜一切,但我无法实现这一目标。 我目前的解决方案如下所示: -
def priority_merge(A, b, keys, mkey):
retval = []
b_index = 0
for elemA in A:
if b_index >= len(b):
break # No more items in b
elemb = b[b_index]
minA = { k: elemA[k] for k in keys }
minb = { k: elemb[k] for k in keys }
if minA == minb: # Found a match
if elemA[mkey] >= elemb[mkey]:
retval.append(elemA)
else: # Check mkey to see if take b instead
retval.append(elemb)
b_index = b_index + 1
else: # No match, check forward by one
if b_index+1 >= len(b):
continue
elembplus = b[b_index+1]
minb = { k: elembplus[k] for k in keys}
if minA == minb:
retval.append(elemb) # This is a new element
if elemA[mkey] >= elembplus[mkey]:
retval.append(elemA)
else:
retval.append(elembplus)
b_index = b_index + 2
if b_index <= len(b):
retval.extend(b[b_index:])
return retval
只要我连续多次添加和/或删除( b
相对于A
),这样就可以正常工作。 因此,如果A
包含1,2,3,5和b
包含1,2,3,4,5就可以了,但如果A
包含1,2,5和b
包含1,2,3,4,5,则会发生故障。
我可以检查len(b),在else情况下注释为# No match, check forward by one
,或者首先迭代A
和b
来映射匹配元素,然后根据该映射再次迭代以创建retval。 这似乎容易出错(我确信它的逻辑可行,但我也很确定我为它编写的代码会有错误)。 请推荐一个合适的算法来解决这个问题,无论是我的两个想法还是别的。
正如我所说的哈希方法可以帮助您确保比较,仅基于keys
列表,您将能够找到交集元素(要合并的元素)和差异元素。
class HashedDictKey(dict):
def __init__(self, keys_, **kwargs):
super().__init__(**kwargs)
self.keys_ = keys_
def __hash__(self):
return hash(tuple(sorted((k, self.get(k)) for k in self.keys_)))
def __eq__(self, other):
return hash(self) == hash(other)
def merge(A, B):
to_be_added = []
to_be_del = []
to_be_updated = []
def get(obj, it):
for i in it:
if obj == i:
return i
raise ValueError("No %s value" % obj)
for a, b in zip_longest(A, B):
if a in B:
to_be_updated.append(a)
if a not in B:
to_be_del.append(a)
if b not in A:
to_be_added.append(b)
for i in to_be_del:
A.remove(i)
for j in to_be_added:
A.append(j)
for i in to_be_updated:
a = get(i, A)
b = get(i, B)
if b['mtime'] > a['mtime']:
A.remove(a)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.