![](/img/trans.png)
[英]Given a list of indexes, how do I split a DataFrame on those indexes?
[英]Given a list of slices, how do I split a sequence by them?
我有很長的氨基酸字符串,我想根據列表中的起止值進行拆分。 一個例子可能是最明確的解釋方式:
str = "MSEPAGDVRQNPCGSKAC"
split_points = [[1,3], [7,10], [12,13]]
output >> ['M', '(SEP)', 'AGD', '(VRQN)', 'P', '(CG)', 'SKAC']
額外的括號是顯示從split_points列表中選擇的元素。 我不認為開始 - 停止點會重疊。
我有一堆可行的想法,但看起來非常低效(代碼長度明智),似乎必須有一個很好的pythonic方式來做到這一點。
你在那里分裂字符串的奇怪方法:
def splitter( s, points ):
c = 0
for x,y in points:
yield s[c:x]
yield "(%s)" % s[x:y+1]
c=y+1
yield s[c:]
print list(splitter(str, split_points))
# => ['M', '(SEP)', 'AGD', '(VRQN)', 'P', '(CG)', 'SKAC']
# if some start and endpoints are the same remove empty strings.
print list(x for x in splitter(str, split_points) if x != '')
這是一個簡單的解決方案。 抓取該點指定的每個集合。
In[4]: str[p[0]:p[1]+1] for p in split_points]
Out[4]: ['SEP', 'VRQN', 'CG']
要獲得括號:
In[5]: ['(' + str[p[0]:p[1]+1] + ')' for p in split_points]
Out[5]: ['(SEP)', '(VRQN)', '(CG)']
這是完成交易的更簡潔方法:
results = []
for i in range(len(split_points)):
start, stop = split_points[i]
stop += 1
last_stop = split_points[i-1][1] + 1 if i > 0 else 0
results.append(string[last_stop:start])
results.append('(' + string[start:stop] + ')')
results.append(string[split_points[-1][1]+1:])
以下所有解決方案都很糟糕,而且比其他任何方式更有趣,不要使用它們!
這更像是一個WTF解決方案,但我想我會發布它,因為它在評論中被要求:
split_points = [(x, y+1) for x, y in split_points]
split_points = [((split_points[i-1][1] if i > 0 else 0, p[0]), p) for i, p in zip(range(len(split_points)), split_points)]
results = [string[n[0]:n[1]] + '\n(' + string[m[0]:m[1]] + ')' for n, m in split_points] + [string[split_points[-1][1][1]:]]
results = '\n'.join(results).split()
還在試圖找出一個班輪,這里有兩個:
split_points = [((split_points[i-1][1]+1 if i > 0 else 0, p[0]), (p[0], p[1]+1)) for i, p in zip(range(len(split_points)), split_points)]
print '\n'.join([string[n[0]:n[1]] + '\n(' + string[m[0]:m[1]] + ')' for n, m in split_points] + [string[split_points[-1][1][1]:]]).split()
並且永遠不應該使用的一個班輪:
print '\n'.join([string[n[0]:n[1]] + '\n(' + string[m[0]:m[1]] + ')' for n, m in (((split_points[i-1][1]+1 if i > 0 else 0, p[0]), (p[0], p[1]+1)) for i, p in zip(range(len(split_points)), split_points))] + [string[split_points[-1][1]:]]).split()
這里有一些可行的代碼。
result = []
last_end = 0
for sp in split_points:
result.append(str[last_end:sp[0]])
result.append('(' + str[sp[0]:sp[1]+1] + ')')
last_end = sp[1]+1
result.append(str[last_end:])
print result
如果你只想要括號中的部分,它會變得更簡單:
result = [str[sp[0]:sp[1]+1] for sp in split_points]
可能不是為了優雅,而是因為我可以在一個oneliner :)
>>> reduce(lambda a,ij:a[:-1]+[str[a[-1]:ij[0]],'('+str[ij[0]:ij[1]+1]+')',
ij[1]], split_points, [0])[:-1] + [str[split_points[-1][-1]+1:]]
['M', '(SEP)', 'PAGD', '(VRQN)', 'NP', '(CG)', 'SKAC']
也許你喜歡它。 這里有一些解釋:
在你的問題中,你傳遞了一組切片,並且隱含地你也希望得到補片組(以生成未加括號的[是英語?]切片)。 所以基本上,每個切片[i,j]缺少先前的jeg [7,10]缺少3和[1,3]缺少0。
reduce
進程列表,並在每一步傳遞到目前為止的輸出 ( a
)加上下一個輸入元素 ( ij
)。 訣竅在於,除了生成普通輸出之外,我們每次都會添加一個額外的變量---一種內存 - 這是在a[-1]
檢索的下一步。 在這個特定的例子中,我們存儲了最后一個j值,因此我們始終擁有完整的信息來提供未加密的子字符串和帶括號的子字符串。
最后,用[:-1]剝離存儲器,並用[str[split_points[-1][-1]+1:]]
中的原始str的其余部分替換。
這是一個將split_points轉換為常規字符串切片然后打印出適當切片的解決方案:
str = "MSEPAGDVRQNPCGSKAC"
split_points = [[1, 3], [7, 10], [12, 13]]
adjust = [s for sp in [[x, y + 1] for x, y in split_points] for s in sp]
zipped = zip([None] + adjust, adjust + [None])
out = [('(%s)' if i % 2 else '%s') % str[x:y] for i, (x, y) in
enumerate(zipped)]
print out
>>> ['M', '(SEP)', 'AGD', '(VRQN)', 'P', '(CG)', 'SKAC']
>>> str = "MSEPAGDVRQNPCGSKAC" >>> split_points = [[1,3], [7,10], [12,13]] >>> >>> all_points = sum(split_points, [0]) + [len(str)-1] >>> map(lambda i,j: str[i:j+1], all_points[:-1], all_points[1:]) ['MS', 'SEP', 'PAGDV', 'VRQN', 'NPC', 'CG', 'GSKAC'] >>> >>> str_out = map(lambda i,j: str[i:j+1], all_points[:-1:2], all_points[1::2]) >>> str_in = map(lambda i,j: str[i:j+1], all_points[1:-1:2], all_points[2::2]) >>> sum(map(list, zip(['(%s)' % s for s in str_in], str_out[1:])), [str_out[0]]) ['MS', '(SEP)', 'PAGDV', '(VRQN)', 'NPC', '(CG)', 'GSKAC']
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.