我有两个不同的词典列表,list_a
和list_b
。第一个字典列表包含核苷酸位点,另一个字典列表包含所有基因的起始和结束坐标。如果该位点落入基因坐标的范围内,那么该位点属于该基因。然而,有时即使一个站点超出范围,它仍然属于该基因。例如,来自list_a
的网站,第二个字典 - 8属于gene_b
。
list_a = [{'Ch': 'I', 'name': 'test_1', 'site': 2}, {'Ch': 'II', 'name': 'test_2', 'site': 8}, {'Ch': 'II', 'name': 'test_3', 'site': 10}]
list_b = [{'Ch': 'I', 'name': 'gene_a', 'start': 1, 'end': 3}, {'Ch': 'II', 'name': 'gene_b', 'start': 3, 'end': 6}]
这是第一部分工作正常。
for item_a in list_a:
for item_b in list_b:
if item_a['Ch'] == item_b['Ch'] and item_a['site'] >= item_b['start'] and item_a['site'] <= item_b['end']:
print item_b['name'], item_a['site']
所以我希望有这样的东西
if item_a['site'] >= item_b['start'] and item_a['site'] >= item_b['end']
and item_a['site'] <= the next site in the next dictionary in list_a...
or the beginning of the next gene in the next dictionary... ???
(我已经想出如何按键排序词典列表)
我尝试使用next()
功能,但无法使其正常工作。
答案 0 :(得分:1)
更有效的方法是将这些部分解析为结构 per Ch
值,按排序顺序:
from collections import defaultdict
import bisect
ranges = defaultdict(list)
for info in list_b:
bisect.insort(ranges[info['Ch']], (info['start'], info['end'], info['name']))
bisect.insort()
调用按排序顺序将新条目插入到列表中,从而为您节省了另一个排序循环。
现在使用此功能在list_a
Ch
值的范围内归位:
for gene in list_a:
for start, stop, name in ranges[gene['Ch']]:
if start <= gene['site'] <= stop:
print name, gene['site']
break
当然,这仍然不会搜索与'stop'参数的下一个匹配,但是后一个循环可以折叠成生成器表达式,适合在{{1函数,并且因为范围已排序,您可以继续搜索下一个站点名称:
next()
for gene in list_a:
site = gene['site']
range = iter(ranges[gene['Ch']])
# skip anything with start > site
name = previous = next((name for start, stop, name in range if start <= site), None)
# search on for a matching stop, looking ahead. If we find a stop < site
# the previous entry matched. If we ran of the end of our options, the last
# entry matched.
for start, stop, name in range:
if site > stop:
previous = name
continue
if start > site:
name = previous
break
print name, site
'iterable'会记住'第一个range
搜索停止的位置,我们可以循环搜索,以便继续从该点搜索合适的next()
值。
请注意,大概stop
值总是等于或大于stop
值;对下一个start
项值进行测试也毫无意义;如果start
为site <= stop
,则True
也 site <= start
。
答案 1 :(得分:0)
我认为你可以做一些更直截了当的事。
在list_b中你可以添加一个名为site的新密钥:你可以设置为(start + end)/ 2。
然后合并list_a和list_b,并按sorted_list中的键(Ch:,site :)对它们进行排序。
然后一次通过sorted_list。如果它是一个基因(来自list_a),请跳过它并跟踪其名称:如果它是一个站点(来自list_b),则将其名称设置为上一个项目的名称:或使用名称:您保存。
可能会对“最接近的事情”进行一些调整,但我相信你可以通过展望你当前的位置并做一些适当的业务逻辑来做到这一点。