Python:使用另一个大字典更新一个大字典

23

我想要使用另一个字典中相似的键(相同的日期但格式不同)来更新大字典中的一些值。目前的方法太慢了,我想要减少瓶颈。

这是我目前的解决方案(它将更新后的字典写入文件):

from dateutil import parser
File = open(r'E:Test1.txt','w')

b = {'1946-1-1':0,..........,'2012-12-31':5}
d = {'1952-12-12':5,........,'1994-7-2':10}

for key1, val1 in b.items():
    DateK1 = parser.parse(key1)
    Value = val1
    for key2, val2 in d.items():
        DateK2 = parser.parse(key2)
        if DateK1 == DateK2:
            d[key2] = Value        

Order= sorted(d.items(), key=lambda t: t[0])

for item in Order:
    File.write('%s,%s\n' % item)
File.close()

为什么在“d”上使用“for”循环?这完全违背了哈希的初衷。在Python shell中执行“print dir({})”,了解每个方法的作用。请尝试一些东西并发布您的工作。 - tuxuday
@tuxuday:我试图在d和b中使用dateutil解析器,但是不正确。请看下面Hayden的回答如何帮助,他将d和b转换以包含解析器(在内部使用“for”),然后更新了字典d。 - Eric Gentil
2
提出的重复问题非常糟糕,甚至从被接受的答案中也无法清楚地了解原始问题的作者想要如何合并。 - Kev
2个回答

38
你应该使用 update 方法来合并字典:
b.update(d)

目前你正在为b中的每个键迭代d... 这是很慢的。你可以通过设置两个字典来解决这个问题,它们将具有相同的键(并且相等的日期将哈希相同 - 这里也许要注意的酷事情是datetime对象可以哈希):

b1 = dict( (parser.parse(k),v) for k,v for b.iteritems() )
d1 = dict( (parser.parse(k),v) for k,v for d.iteritems() )

d1.update(b1) # update d1 with the values from b1

编辑:

我刚刚意识到你不完全是在进行更新,因为只有那些共享的值被更新了,所以改为(再次仅迭代一次):

for k_d1 in d1:
    if k_d1 in b1:
        d1[k_d1] = b1[k_d1]

那么我该如何避免迭代呢?因为我必须解析键,以便读取“日期”...一些键在两个字典中可能是相同的日期,但格式略有不同:例如“1946-1-1”和“1946-01-1”或“1946-01-01”。 - Eric Gentil
@EricGentil 哦,好的,我已经更新了它们的解析方式,这样可以让它们以相同的格式呈现,这个解决方案对你来说好吗?(这应该是可行的,因为日期时间是可哈希的。) - Andy Hayden
1
@EricGentil 添加了编辑,因为您只更新已经在 d 中的内容(我的错误!) - Andy Hayden
@hyden:你的想法可行,但我认为第二个“for”应该是“in”,像这样 b1 = dict((parser.parse(k),v) for k,v in b.iteritems()) ..对吗? - Eric Gentil
@ hayden:我意识到你的答案可能不正确:你还必须迭代b1。我发布的代码给了我正确的答案,但速度非常慢(经过几个小时)。wberry建议在我的常规代码中只使用d.iteritems而不是d.items()(对于b也是如此),这可能会节省一些时间...但我必须检查,因为代码仍在运行(十几分钟后)。 - Eric Gentil
显示剩余4条评论

3

建议更改:

  1. 使用 .iteritems() 替代 .items()。你现在的方法会创建一个键值对列表并遍历它,这是浪费的。
  2. 你说 bd 中的日期格式不同。我猜月份和日期被交换了?如果是这样的话,你可以通过计算出 d 键应该是什么,然后检查其成员资格来节省大量时间。

更改后的代码:

def switch_month_day(datestr):
  fields = datestr.split("-")
  return "%s-%s-%s" % (fields[0], fields[2], fields[1])

for key, val in b.iteritems():
  DateK = switch_month_day(key)
  if DateK in d:
    d[DateK] = val

你提出了一个很好的观点。我没有注意到解析器可能不考虑年月日的顺序...我在检查之前就接受了答案...但让我仔细检查哪个给我正确的答案! - Eric Gentil
根据问题中字典键的格式,我编辑了我的答案以使用switch_month_day(key)而不再使用parser函数。 - wberry
dateutil解析器非常有用,因为如果某个数据点的日期中有空格或者使用了“-”之外的其他符号,它都可以读取任何格式的日期和时间,并将它们协调成相似的形式,这在排序时非常有帮助。那么你认为这个解析器会减慢代码吗? - Eric Gentil
很可能不会造成显著的减速。使用 iteritems 并且不对两个字典进行二次时间迭代,这很可能比那更重要。我只是在考虑如何切换月份和日期,而你的问题并没有完全清楚是否需要这样做。 - wberry

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接