0

我有两个不同的字典列表,list_alist_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()功能,但无法使其正常工作。

4

2 回答 2

1

更有效的方法是将这些部分解析为每个 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' 参数搜索下一个匹配项,但是后面的循环可以折叠成生成器表达式,适合在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

range迭代的“记住”第一次next()搜索停止的位置,我们可以循环它以从该点继续搜索合适的stop值。

请注意,这些stop值可能总是等于或大于这些start值;也没有必要针对下一个项目start值进行测试;如果site <= stopTrue那么site <= start也是。_ True

于 2013-09-06T08:36:32.970 回答
0

我认为您也许可以做一些更直接的事情。

在 list_b 中,您可以添加一个名为 site: 的新键,您可以将其设置为 (start+end)/2。

然后合并list_a和list_b,并在sorted_list中按key(Ch:,site:)排序。

然后一次通过 sorted_list。如果它是一个基因(来自 list_a),则跳过它并跟踪其名称:如果它是一个站点(来自 list_b),则将其名称设置为上一个项目的名称:或使用名称:您保存。

可能会对“最接近的事情”进行一些调整,但我相信你可以通过展望你当前的位置并做一些适当的业务逻辑来做到这一点。

于 2013-09-11T05:21:26.423 回答