在字典列表中查找与给定值匹配的值

4

我有一个字典列表,看起来像这样:

serv=[{'scheme': 'urn:x-esri:specification:ServiceType:DAP',
  'url': 'http://www.esrl.noaa.gov/psd/thredds/dodsC/Datasets/air.mon.anom.nobs.nc'},
 {'scheme': 'urn:x-esri:specification:ServiceType:WMS',
  'url': 'http://www.esrl.noaa.gov/psd/thredds/wms/Datasets/air.mon.anom.nobs.nc?service=WMS&version=1.3.0&request=GetCapabilities'},
 {'scheme': 'urn:x-esri:specification:ServiceType:WCS',
  'url': 'http://ferret.pmel.noaa.gov/geoide/wcs/Datasets/air.mon.anom.nobs.nc?service=WCS&version=1.0.0&request=GetCapabilities'}]

我希望找到与ServiceType:WMS相对应的URL,这意味着在此列表中查找scheme键具有值urn:x-esri:specification:ServiceType:WMS的字典中url键的值。
所以我有一个可以工作的代码:
for d in serv:
    if d['scheme']=='urn:x-esri:specification:ServiceType:WMS':
        url=d['url']
print url

它产生

http://www.esrl.noaa.gov/psd/thredds/wms/Datasets/air.mon.anom.nobs.nc?service=WMS&version=1.3.0&request=GetCapabilities

但我刚刚看了Raymond Hettinger的PyCon演讲,他在结尾处说如果你可以用一句话表达它,就应该用一行Python来表达。

那么是否有更美观、惯用的方法来实现相同的结果,也许只需要一行Python?

谢谢, Rich

5个回答

2
如果你只对一个URL感兴趣,那么你可以在“serv”上构建一个生成器,并使用“next”来设置默认值,以处理找不到匹配项的情况,例如:
url = next((dct['url'] for dct in serv if dct['scheme'] == 'urn:x-esri:specification:ServiceType:WMS'), 'default URL / not found')

这很酷,因为它预见到了我要查找的serviceType不在列表中的问题。我认为这是最好的通用答案,尽管对于我的特定情况,我会采用Nikita的解决方案,将我的字典列表转换为单个字典。 - Rich Signell
它还代表了Hettinger所建议的最佳表达方式,就像这个句子一样,你可以从左到右阅读它:“迭代直到找到方案与特定字符串匹配的URL,否则使用默认值”。 - Rich Signell

2

您列出的serv数组看起来像是将方案映射到URL的字典,但它并没有被表示为这样。不过您可以使用列表推导式轻松地将其转换为dict,然后使用普通的字典查找:

url = dict([(d['scheme'],d['url']) for d in serv])['urn:x-esri:specification:ServiceType:WMS']

当然,你可以保存字典版本以备将来使用(但需要使用两行代码)。
servdict = dict([(d['scheme'],d['url']) for d in serv])
url = servdict['urn:x-esri:specification:ServiceType:WMS']

你说得完全正确——这个字典列表确实应该是一个将服务类型与URL匹配的单个字典。虽然其他人提供的答案更普遍适用,但对于这个特定的情况,这就是我在我的代码中要采用的答案。 - Rich Signell

2
我建议将此拆分为两行,以区分目标和url检索。这是因为您的目标可能随时间而变化,因此不应硬编码。以下是单行代码。
我建议使用in代替==,因为我们要搜索所有属于此类型的方案。这增加了更多的灵活性和可读性,假设这也不会捕捉到其他不需要的方案。但从描述中可以看出,这是所需的功能。
target = "ServiceType:WMS"
url = [d['url'] for d in serv if target in d['scheme']]

此外,请注意,无论何种情况下都会返回列表,以防有多个匹配项,因此您将不得不在使用此代码的代码中循环访问 url

我喜欢使用in而不是==。好的提示! - Rich Signell

1
这个怎么样?
urls = [d['url'] for d in serv if d['scheme'] == 'urn:x-esri:specification:ServiceType:WMS']

print urls # ['http://www.esrl.noaa.gov/psd/thredds/wms/Datasets/air.mon.anom.nobs.nc?service=WMS&version=1.3.0&request=GetCapabilities']

它正在执行与您的代码相同的操作,其中d [ 'url']被附加到列表urls中,如果它们以WMS结尾,则会进行附加。
您甚至可以添加一个else子句:
urls = [i['url'] for i in serv if i['scheme'].endswith('WMS') else pass]

我喜欢这个答案,因为它向我展示了如何将我的逻辑转换为一行代码。很酷。 - Rich Signell

1

我一直在尝试将更多的函数式编程应用到自己的工作中,所以这里提供一种相当简单的函数式方法:

needle='urn:x-esri:specification:ServiceType:WMS'
url = filter( lambda d: d['scheme']==needle, serv )[0]['url']
filter函数接受一个返回布尔值的函数和一个需要过滤的列表作为参数。它返回一个由传递给返回布尔值函数时返回True的元素组成的列表(在这种情况下,我临时定义了一个lambda函数)。因此,要最终获取URL,我们必须取filter返回的列表的第零个元素。由于那是包含所需URL的字典,我们可以在整个表达式末尾标记['url']以获取相应的字典条目。

不错 - 我可以看到在更复杂的情况下使用该测试函数的威力。 - Rich Signell

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