通过多个对象属性过滤对象列表

0 投票
2 回答
1234 浏览
提问于 2025-04-18 01:55

我正在使用 NDB API 构建一个 Google App Engine 应用程序(Python 2.7)。我对 Python 开发还很陌生,感觉这个问题可能之前有人问过,但我在搜索时找不到类似的问题或解决方案。所以我决定在这里提问。

我有一个文档模型类,我需要查询并获取最新的文档。具体来说,我想要获取一组文档对象(实体),这些文档的名称是独一无二的,并且它们的 expiration 日期(一个 datetime.date 对象)是最大的。

举个例子,我想按过期日期降序查询文档,像这样:

documents = Document.query().order(-Document.expiration).fetch()

返回的结果是:

[{"name": "DocumentC", "expiration": datetime.date(2015, 3, 1)},
 {"name": "DocumentA", "expiration": datetime.date(2014, 4, 1)},
 {"name": "DocumentB", "expiration": datetime.date(2014, 2, 15)},
 {"name": "DocumentA", "expiration": datetime.date(2014, 1, 1)}] 

根据这些查询结果,我想去掉第二个(较旧的)“DocumentA”,得到类似这样的结果:

[{"name": "DocumentC", "expiration": datetime.date(2015, 3, 1)},
 {"name": "DocumentA", "expiration": datetime.date(2014, 4, 1)},
 {"name": "DocumentB", "expiration": datetime.date(2014, 2, 15)}]

我的解决方案是:

def current_docs(docs):
    output = []
    for d in docs:
        if not any(o['name'] == d['name'] for o in output):
            output.append(d)
    return output

cd = current_docs(documents)
# returns:
# [{'expiration': datetime.date(2015, 3, 1), 'name': 'DocumentC'},
# {'expiration': datetime.date(2014, 4, 1), 'name': 'DocumentA'},
# {'expiration': datetime.date(2014, 2, 15), 'name': 'DocumentB'}]

这个方法似乎能给我想要的结果,但:

  1. 有没有更好的方法可以从一开始就过滤原始查询,以获得我想要的结果?
  2. 如果没有,是否有比我的解决方案更好、更有效的方法?

2 个回答

0

只要你的数据符合文档中提到的限制,你就可以使用一种叫做投影查询的方法,并设置 group_by=["name"]distinct=True 来实现这个功能。

另外,我建议你把数据保存到一个预先计算好的表里,这个表只包含唯一的文档名称和最新的数据/状态。虽然在写入数据时会增加一些成本,但这样你可以快速读取数据,而且不需要依赖于未过滤的数据集适应实例内存,这在你打算在运行时进行过滤时是必须的。

0

我对你第二个问题的看法是:

def current_docs(docs):
  tmp = {}
  output = []
  for d in docs:
    if d['name'] in tmp:
      continue
    tmp[d['name']] = 1
    output.append(d)
  return output

保持一个已经添加过的名字的字典,只添加那些还没有被添加的名字。不过我对Google App Engine不太了解哦 :)

撰写回答