为了账号安全,请及时绑定邮箱和手机立即绑定

带有 if else 条件的 Python 列表理解

带有 if else 条件的 Python 列表理解

繁星点点滴滴 2022-05-19 14:21:18
我有一个小 (<100) 化学名称列表,称为detected_chems.还有第二个更大(> 1000)的可迭代;chem_db包含化学名称的字典作为键,化学特性字典作为值。像这样:{'chemicalx':{'property1':'smells','property2':'poisonous'}, 'chemicaly':{'property1':'stinks','property2':'toxic'}}我正在尝试将所有检测到的化学物质与数据库中的化学物质进行匹配并提取它们的属性。所以我正在制作一个结果列表,但是我创建了这个res,而不是嵌套的带有条件的循环。if x inres = [{chem:chem_db[chem]}       for det_chem in detected_chems       for chem in chem_db.keys()       if det_chem in chem]这在一定程度上有效!我(认为)在这里做的是创建一个字典列表,如果发现检测到的化学物质,它将具有化学名称(键)的键:值对和有关化学物质的信息(作为字典本身,作为值)化学数据库(chem_db)中的某处。问题不是所有检测到的化学物质都在数据库中找到。这可能是由于拼写错误或名称变化(例如,它们包括数字)或类似的原因。所以为了解决这个问题,我需要确定哪些检测到的化学物质不匹配。我认为这可能是一个解决方案:not_matched=[]res = [{chem:chem_db[chem]}       for det_chem in detected_chems       for chem in chem_db.keys()       if det_chem in chem else not_matched.append(det_chem)]由于部分原因,我收到语法错误else not_matched.append(det_chem)。我有两个问题:1)我应该把 else 条件放在哪里以避免语法错误?2)可以在not_matched列表理解中构建列表,所以我不会先创建那个空列表。res = [{chem:chem_db[chem]}       for det_chem in detected_chems       for chem in chem_db.keys()       if det_chem in chem else print(det_chem)]我想要实现的是:in: len(detected_chems)out: 20in: len(res)out: 18in: len(not_matched)out: 2in: print(not_matched)out: ['chemical_strange_character$$','chemical___WeirdSPELLING']这将帮助我找到匹配问题。
查看完整描述

3 回答

?
胡说叔叔

TA贡献1804条经验 获得超8个赞

你应该


if det_chem in chem or not_matched.append(det_chem)

但话虽如此,如果您根据评论进行一些清理,我认为有一种更有效的方式来做您想做的事。上面的解释是append返回None所以整个 if 条件将评估为False(但该项目仍附加到not_matched列表中)


回复:效率:


res = [{det_chem:chem_db[det_chem]}

       for det_chem in detected_chems

       if det_chem in chem_db or not_matched.append(det_chem)]

这应该会更快det_chem in chem_db- 字典键上的 for 循环是一个 O(n) 操作,而使用字典正是因为查找是 O(1) 所以我们使用哈希查找而不是检索键并一一比较它们基于


奖励:dict理解(解决问题2)


我不确定为什么要构建一键字典列表,但可能需要的是字典理解,如下所示:


chem_db = {1: 2, 4: 5}

detected_chems = [1, 3]

not_matched = []

res = {det_chem: chem_db[det_chem] for det_chem in detected_chems if

       det_chem in chem_db or not_matched.append(det_chem)}

# output

print(res) # {1: 2}

print(not_matched) # [3]

我无法想到在构建not_matched列表的同时还res使用单个列表/字典理解进行构建。


查看完整回答
反对 回复 2022-05-19
?
开心每一天1111

TA贡献1836条经验 获得超13个赞

您的语法错误来自于理解不接受else子句的事实。


您最终可以使用... if ... else ...三元运算符来确定要放入您的理解结果的值。如下所示:


not_matched=[]

res = [{chem:chem_db[chem]} if det_chem in chem else not_matched.append(det_chem)

       for det_chem in detected_chems

       for chem in chem_db.keys()]

但这将是一个坏主意,因为您将None在您的resfor each notmatched中。这是因为... if ... else ...运算符始终返回一个值,在您的情况下,该值将是list.append方法的返回值(= None)。然后,您可以过滤res列表以删除None值,但是......嗯......


更好的解决方案是简单地保持您的第一理解并获得原始chem列表和列表之间的差异res:


not_matched = set(chems).difference(<the already matched chems>)

请注意,我使用了已经匹配的 chems占位符而不是真正的代码块,因为您的存储方式res根本不实用。事实上,它是一个单键字典列表,这是不合理的。字典的作用是保存由键标识的多个值。


对此的解决方案是res使用字典理解来制作字典而不是列表:


res = {chem: chem_db[chem]

       for det_chem in detected_chems

       for chem in chem_db.keys()

       if det_chem in chem}

这样做,已经匹配的化学占位符可以替换为res.values()


另外,即使在很多情况下推导是一个非常酷的功能,它们也不是一个应该在任何地方都使用的神奇功能。嵌套理解真的很难读,应该避免(至少在我看来)。


查看完整回答
反对 回复 2022-05-19
?
湖上湖

TA贡献2003条经验 获得超2个赞

列表理解形式上最多包含 3 个部分。让我们在一个例子中展示它们:

[2 * i          for i in range(10)         if i % 3 == 0]
  1. 第一部分是一个表达式——它可能是(或在其中使用)三元运算符x if y else z)

  2. 第二部分是一个列表或嵌套for循环中的更多列表),用于从中选择变量的值。

  3. 第三部分(可选)是一个过滤器(用于在2 部分中进行选择) -这里不允许使用子句!else

所以如果你想使用else分支,你必须把它放到第一部分,例如

[2 * i  if i < 5  else 3 * i           for i in range(10)          if i % 3 == 0]


查看完整回答
反对 回复 2022-05-19
  • 3 回答
  • 0 关注
  • 148 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信