我上一个问题的延续,使用第二个答案 - http://tinyurl.com/n9dybgb
我正在比较 DNA 中的核苷酸位置,其中位置的形式为 [染色体、开始、停止],并且我有一个现有位置列表和一个新位置列表。目的是将新位置列表与现有位置进行比较,并添加新位置元素之一(如果它是唯一的或与现有位置重叠)。如果重叠,则应报告。只有当新位置元素完全包含在现有元素中时,才应将其丢弃。
感谢@Hugh Bothwell - 我目前有这段代码:
class ChromoSegments:
def __init__(self, ChromoSegments_args=None):
#Creates an empty default dict list which can be added to in the style "chromo[start,end]", and will stay ordered
self.segments = defaultdict(list)
#If a list is passed to the constructor you can add values to your list depending on conditions in 'add_seg'
if ChromoSegments_args is not None:
for chromo,start,end in ChromoSegments_args:
try:
self.add_seg(chromo, start, end)
except ValueError:
pass
#function for adding positions to the expos list
def add_seg(self, chromo, start, end):
seg = self.segments[chromo]
val = (start, end)
ndx = bisect_left(seg, val)
if (ndx == 0 or seg[ndx - 1][1] < start):
if (ndx == len(seg) or end < seg[ndx][0]):
seg.insert(ndx, val)
else:
nstart, nend = seg[ndx]
raise ValueError("Hit ({}, {}, {}) \t\t\t overlaps with ({}, {}, {})".format(chromo, start, end, chromo, nstart, nend))
#collision with preceding element
else:
nstart, nend = seg[ndx - 1]
raise ValueError("Hit ({}, {}, {}) \t\t\t overlaps with ({}, {}, {})".format(chromo, start, end, chromo, nstart, nend))
def to_list(self):
keys = sorted(self.segments.keys())
return [(k, s, e) for k in keys for s,e in self.segments[k]]
def main():
expos = ChromoSegments(expos_list)
newpos = (newpos_list)
error_file = open("discarded_hits.txt", "w")
for seg in newpos:
try:
expos.add_seg(*seg)
except ValueError, e:
collision = str(e)
error_file.write(collision + "\n")
error_file.close()
#convert results back into text files of positions
updated_expos = expos.to_list()
updated_expos_file = open(sys.argv[2], "w")
for element in updated_expos:
c1 = str(element[0])
c2 = str(element[1])
c3 = str(element[2])
updated_expos_file.write(c1 + "\t" + c2 + "\t" + c3 + "\n")
updated_expos_file.close()
if __name__ == "__main__":
main()
这会获取先前创建的列表“expos_list”和“newpos_list”,然后丢弃所有与现有元素有任何重叠的匹配项。请有人在 add_seg 函数中建议一组不同的/更好的 if 语句,以便仅丢弃完全包含在现有元素中的匹配项?我真的很难让语法正确!非常感谢!
示例列表:
expos_list = [[1, 20, 40], [1, 60, 80]]
newpos_list = [[1, 12, 25], [1, 22, 38], [1, 75, 90], [1, 100, 150]]
所以,在一个成功的过程之后,我想要一个最终的 expos_list(记住第一个数字(目前在所有情况下都是 1)可以是任何东西:
expos_list = [[1, 12, 25], [1, 20, 40], [1, 60, 80], [1, 75, 90], [1, 100, 150]]
请您参考如下方法:
我试一试:
START = 1
END = 2
expos_list = [[1, 20, 40], [1, 60, 80]]
newpos_list = [[1, 12, 25], [1, 22, 38], [1, 75, 90], [1, 100, 150]]
# sort the new list
expos_list.extend(newpos_list)
expos_list.sort(lambda l1, l2: cmp(l1[0], l2[0]) or (l1[0] == l2[0] and (cmp(l1[1], l2[1]) or (l1[1] == l2[1] and (cmp(l1[2], l2[2]))))))
# remove and print the overlaps
i = 0
l = expos_list
while i < len(l) - 1:
if l[i][END] > l[i + 1][START]:
print 'overlap', l[i], l[i+1]
if l[i][START] <= l[i+1][START] and l[i][END] >= l[i+1][END]:
# i+1 is in i
l.pop(i+1)
elif l[i][START] >= l[i+1][START] and l[i][END] <= l[i+1][END]:
# i is in i+1
l.pop(i)
else:
# there is a partial overlap
i += 1
else:
i += 1
# overlap [1, 12, 25] [1, 20, 40]
# overlap [1, 20, 40] [1, 22, 38]
# [1, 22, 38] # removed
# overlap [1, 60, 80] [1, 75, 90]
# outcome
print expos_list
# [[1, 12, 25], [1, 20, 40], [1, 60, 80], [1, 75, 90], [1, 100, 150]]
此代码删除所有完全重叠的元素并打印所有重叠
以下行可用于 Python 3:
lambda l1, l2: l1[0] < l2[0] or (l1[0] == l2[0] and (l1[1] < l2[1] or (l1[1] == l2[1] and (l1[2] <= l2[2]))))
