这个问题有点老了,但是很有趣,因为您有一个非常清晰的规范,并且需要帮助来编写代码。我将采用自上而下的方法公开一个解决方案,这是一种众所周知的方法,使用普通的旧 python。适应熊猫应该不难。
自上而下的方法对我来说意味着:如果你不知道怎么写,就直接命名吧!
您有一个文件(或一个字符串)作为输入,并且您想要输出一个文件(或一个字符串)。这看起来很简单,但您想要合并行对来构建每个新行。这个想法是:
- 获取输入的行,作为字典
- 把他们分成两个
- 为每对建立一个新行
- 输出结果
您现在不知道如何编写行生成器。您也不知道如何为每对构建新行。不要被困难所阻碍,只提出解决方案。假设你有一个函数get_rows
和一个函数build_new_row
。我们这样写:
def build_new_rows(f):
"""generate the new rows. Output may be redirected to a file"""
rows = get_rows(f) # get a generator on rows = dictionaries.
r1 = next(rows) # store the first row
for r2 in rows: # for every following row
yield build_new_row(r1, r2) # yield a new row built of the previous stored row and the current row.
r1 = r2 # store the current row, which becomes the previous row
现在,检查两个“缺失”的函数:get_rows
and build_new_row
。
功能get_rows
很容易写。这是主要部分:
header = process_line(next(f))
for line in f:
yield {k:v for k,v in zip(header, process_line(line))}
where process_line
只是在空间上分割线,例如与一个re.split("\s+", line.strip())
.
第二部分是build_new_row
。仍然是自上而下的方法:您需要从预期的表中构建 H0 和 H1,然后根据您暴露的条件为每个 M 和 S 构建 H1 的计数。假装你有一个pipe_compute
计算 H0 和 H1 的函数,以及build_count
为每个 M 和 S 构建 H1 计数的函数:
def build_new_row(r1, r2):
"""build a row"""
h0, h1 = pipe_compute(r1["F1_hybrid"], r2["F1_hybrid"])
# initialize the dict whith the pos, H0 and H1
new_row = {"pos":r2["pos"], "H0":h0, "H1":h1}
for key in r1.keys():
if key[0] in ("M", "S"):
new_row[key] = build_count(r1[key], r2[key], h1)
return new_row
你现在几乎拥有了一切。看一眼pipe_compute
: 这正是你在条件03中所写的。
def pipe_compute(v1, v2):
"""build H0 H1 according to condition 03"""
xs = v1.split("|")
ys = v2.split("|")
return [ys[0]+"g"+xs[0], ys[1]+"g"+xs[1]]
And for buid_count
,坚持自上而下的方法:
def build_count(v1, v2, to_count):
"""nothing funny here: just follow the conditions"""
if is_slash_count(v1, v2): # are conditions 01, 02, 04 true ?
c = slash_count(v1, v2)[to_count] # count how many "to_count" we find in the 2 x 2 table of condtions 01 or 02.
elif "|" in v1 and "|" in v2: # condition 03
c = pipe_count(v1, v2)[to_count]
elif "." in v1 or "." in v2: # condition 05
return '0'
else:
raise Exception(v1, v2)
return "{}-{}".format(c, to_count) # n-XgY
我们还在往下走。我们什么时候有is_slash_count
?两条斜线(条件 01 和 02)或一条斜线和一根竖线(条件 04):
def is_slash_count(v1, v2):
"""conditions 01, 02, 04"""
return "/" in v1 and "/" in v2 or "/" in v1 and "|" in v2 or "|" in v1 and "/" in v2
功能slash_count
就是条件 01 和 02 的 2 x 2 表:
def slash_count(v1, v2):
"""count according to conditions 01, 02, 04"""
cnt = collections.Counter()
for x in re.split("[|/]", v1): # cartesian product
for y in re.split("[|/]", v2): # cartesian product
cnt[y+"g"+x] += 1
return cnt # a dictionary XgY -> count(XgY)
功能pipe_count
甚至更简单,因为你只需要计算结果pipe_compute
:
def pipe_count(v1, v2):
"""count according to condition 03"""
return collections.Counter(pipe_compute(v1, v2))
现在你已经完成了(并且结束了)。我得到这个结果,与您的期望略有不同,但您肯定已经看到了我的错误:
pos M1 M2 Mk Mg1 H0 H1 S1 Sk1 S2 Sj
16229783 4-CgT 4-CgT 4-CgT 1-CgT GgC CgT 0 1-CgT 1-CgT 1-CgT
16229992 4-AgC 4-AgC 4-AgC 1-AgC GgG AgC 2-AgC 2-AgC 2-AgC 1-AgC
16230007 4-TgA 4-TgA 4-TgA 1-TgA AgG TgA 2-TgA 2-TgA 2-TgA 0-TgA
16230011 4-GgT 4-GgT 4-GgT 2-GgT CgA GgT 1-GgT 1-GgT 1-GgT 1-GgT
16230049 4-AgG 4-AgG 4-AgG 4-AgG TgC AgG 1-AgG 0 1-AgG 1-AgG
16230174 0 0 0 4-CgA TgT CgA 1-CgA 0 1-CgA 1-CgA
16230190 0 0 0 4-AgC TgT AgC 0-AgC 0-AgC 0-AgC 0-AgC
16230260 4-AgA 4-AgA 4-AgA 4-AgA GgT AgA 0-AgA 0-AgA 0-AgA 0-AgA
Bonus: 在线尝试一下! https://tio.run/##lVZtb@M2DP6eX0G4H5qgsWO7XXvNUAxFsKU3oLgB7YcNucBwbDlW41iZrLxd09/ekZLtOD3fhgWgI4lvj0iK0mqvUpFfvr@fQSRins@HsFaJ/alzBqlSq2I4GBQqjBZiw2SSia0TieXg7zUrFBd5MbjyXc@/uXQHqdjaStiShbGttsLOeM4KO5FiaYd2wjNmh3lsR8hXzI73ebjkUWEv2L6weU4iQtqZECt7XSAIe9Xp8OVKSAVcVCPJqlEksoxFGkG1VOzrYVRsOh21U3AHlmVFqYSVKKD6PXpIPtICaY6T37wg3c8kjzUbZ3@My8EsE9GCxk8o9rTwaOTr@UuH/r1r37@9ub6hpefBc01jpNHhGbyDCzf@NYBD/FFFDd1Pl6Q7wvWK7pHGhxG4B0/rjmle0ugwPure3moo94P7msZEh/vab5N3f9S9dF33O8z3RA3MNG5QQ9ejOKCv8Qkhtlq3xKppfNwv6l7dfsRM9NzEjP4cLaMxHXW9myvSdRpE8XrGWFW6FHOaE42amL1b97/8PhNWrT8mOur61626zTh/iAUWXacTswRma57FQc62gRTbopv0hh0yhfw5y5nEkwAqZYACQAIOfFmr1VrBMtzDjGG9x1ximbMYlIAQ6BSRbbJB8ljfc6Yq22bZw8Wc7VSXVs0aniyQPvBcKxkI9NtzlsWnGLvS66Nsr5bR9qRvttNwVm9kXG1EA6LjrmFCxhcMxOwF4TsV5jMoVhlXIHII8z1Owog5mrOSImJFEVDTQIdZuJzFIdBsiFFwtFrX@lpcWH296hRK8lW31@to9RSbDpOo2LTT1WFIescgaOsYhuRjDF4Xw42WWPQ3JPANbRub/VOT9On13lqyW0WuDozmYtKQNwTPARViQAqxZLAJM2yfJlbS/xl8B/vZEvNuqsGwq5ilbh9SSsKKr1hQyqGziVW3LWtKnk8Wyric4Wa44mHGvxnbMY8UbFOuUj3FttiHBxezEcODp1XK7aDDVwvZ1pAs0wCdWA@uNSRA1oOHA@@tU4cW@7guMM@hjt7tHSPME2JO3Cnxu9YjZtB6shoCDa8TlJyiaxPZSKxzRVulVb1FM0i9cnuSqbXMK2WTlJMwbTAnm@9ykvFCQRhFQtJ1R0crEnnM6TYB97IK/I6O18arau9gmTra62X/43IJZbIvcKcX1ty62NGoj/ITr17wptNm6ZgNGpB9xGEWjnBzoVJCmKxzPC4pk3gaXtYIPsHrD3NEKayh1xWDAedFUGRhkZ546A2xHkLZVAEXOS76dq9AyTWDX@B3so@XMx4U5dQ5inDTLRYnFeYp0OsBB4DPAGxfCNeqeBZsGfYELDEsAILsww5JhTNsEyLRcCo0gKXk4nn4HgXLcF8YbjKy8XTFVjN/qL0fU3gCuyyIVtQNy05lGRFUk4@Gfzq2RZPuc/e8NFGwY0HLkBcMft1FbEV6lduTmrVe3@zXN8vBs7MMVTdqpB995vaf879MpfwglVWJtOayviNKX4OTqJUzX@900BpQzTq0ahlU/w6J6qD9fLWhjHJ6qDVedM6ILDDZPXbunW4u9UUwOQym2Ec2XqONkNi@Xcz/0G3Q42RvzuQULu7Aa0YLmSed5P9usdFCKostW2trUz3jdxnyvGqgCUaGC@cJb7t8/vlLFx@1VB/66qAHbv0saN63p1ei6d7YdB89/fX1d6G/c72EXd20dOrM5rswf1r26cUyB4Wu/9MLOh7CJJ4spuYKoOAbt1NT61vJlcaAD3LHTLr4TMfLOxZr1YcYj96SVu/Ov6rzXkOnlMZr1RhsPGTIyw/eVW36FeiupPjiSQ8C6itBAHd3cB4EFO0gODcGTOg77@//AA
重要的是,除了这个具体问题的解决方案之外,我使用的方法以及在软件开发中广泛使用的方法。代码可能会改进很多。