2015-12-07 53 views
4

刪除子我有以下的相當簡單的片斷:的Python:通過指數

def delete_substring_blocks(s, blocks):                    
    '''                             
     s: original input string                     
     blocks: list of indices (start, end) to be deleted                 

     return string `out` where blocks are deleted from s              
    '''                             
    out = ''                            
    p = 0                             
    for start, end in blocks:                        
     out += s[p:start]                        
     p = end                           
    out += s[p:]                           
    return out 

此功能需要一個字符串ss,其中指數(start, end)的成對列表中的blocks給出刪除所有s[start:end]

是否有一個內置函數在做同樣的事情?


更新: 有一個在我的代碼的假設:

  1. 塊由第一個索引以升序(由list.sort()就地完成)

至於排序如果塊可以重疊,在我的用例中,我確保它們不會在調用該函數之前。但爲了好玩,我們還可以假設他們:)

+0

可以了'(開始,結束)'塊重疊? – ziddarth

+0

不......作爲一般規則,沒有內建函數用於你需要做的每一件任意事情...... – donkopotamus

回答

3

我的做法轉變blocks爲一組,我稱之爲exclude指數。之後,遍歷字符串並排除索引位於exclude集合中的那些字符。我使用集合而不是列表,因爲它很好地處理重複項(在重疊範圍的情況下)。

構建的exclude設置

給定範圍的無序,有可能重疊的名單:

blocks = [(5, 7), (2, 4), (6, 10)] 

我想這個轉換爲:

exclude = {2, 3, 5, 6, 7, 8, 9} 

如何:

exclude = set() 
for block in blocks: 
    exclude.update(range(*block)) 

把它放在一起

這是我的代碼和最後一個小例子。請注意,我選擇重命名該函數,因爲此函數足夠通用,可以處理字符串,列表,元組和其他可迭代對象,而不僅僅是字符串。另外,因爲該函數返回一個列表,所以在處理字符串時,我們需要將字符列表連接在一起。

def delete_blocks(iterable, blocks):                    
    exclude = set() 
    for block in blocks: 
     exclude.update(range(*block)) 
    return [cell for i, cell in enumerate(iterable) if i not in exclude] 

# Try it out 
test_string = 'abc' 
blocks = [(5, 7), (2, 4), (6, 10)] 
result = ''.join(delete_blocks(test_string, blocks)) 

print('Before: {!r}'.format(test_string)) 
print('Blocks:', blocks) 
print('After: {!r}'.format(result)) 

更新:使用delete_blocks實現delete_substring_blocks

要真正回答麥的問題,我實現delete_substring_blocks

def delete_substring_blocks(s, blocks): 
    return ''.join(delete_blocks(s, blocks)) 
0

您需要按逆序排列順序處理塊,否則字符串的預期部分將更改位置,並且塊索引將失效。

這將是這樣的:

def delete_substring_blocks(s, blocks): 
    ''' 
     s: original input string 
     blocks: list of indices (start, end) to be deleted 

     return string `out` where blocks are deleted from orig_str 
    ''' 
    for start, end in reversed(sorted(blocks)): 
    s = s[:start] + s[end:] 
    return s 
+0

不確定在這裏,但是's = s [:...]'有意改變了從OP 's + = s [:...]' – Zizouz212

+0

該函數不會處理重疊塊 – donkopotamus

+0

(1)'tmp'和'p'未被使用。 (2)這段代碼不會工作,因爲每次迭代'''變得更短。我建議你測試一下。 – Mai

-1

號你問什麼是相當具體。如果你想指定你想要保留的字符串部分(而不是刪除),你可以很容易地把它排成一行。

>>> string = 'my long string' 
>>> ''.join([string[s:e] for s, e in [(0,3), (8, 14)]]) 
'my string' 
+0

這不會處理重疊塊,並假定它們已排序,並且不回答實際問題。 – donkopotamus

+0

@donkopotamus我的回答是正確的。問的唯一問題是是否有內置的函數來執行發佈的函數。唯一正確的答案是 –

+0

@donkopotamus此外,重疊塊的要求沒有在問題中提到。這是你施加的一個人爲限制。 –

0

由於未指定,因此我們必須假定塊的列表可能包含重疊。

甲相對低效表達,但一個將要處理的重疊和非排序的塊,是:

def delete_substring_blocks(s, blocks): 
    return ''.join(
     [c for i, c in enumerate(s) 
     if not any(blk for blk in blocks 
        if i >= blk[0] and i < blk[1])]) 

在這裏,我們簡單地測試每一個字符的位置,看它是否是內的任何塊的時間間隔的,並接受如果不是的話。

這裏是重疊塊的例子:

>>> delete_substring_blocks(
     "hello there how are you", 
     [[0, 3], [7, 9], [7, 10]]) 
'lo te how are you' 

正如你似乎找到這個表達不可讀的,在這裏它被分解多一點:

def delete_substring_blocks(s, blocks): 
    def check_pos(i): 
     return not any(1 for start, end in blocks 
         if i >= start and i < end) 

    return ''.join([c for i, c in enumerate(s) 
        if check_pos(i)]) 
+0

不可讀=不是Pythonic。 – Mai

0

這是一個基於解決方案在位圖上。它可以處理重疊塊:

def delete_substring_blocks(s, blocks): 
    # create a bitmap with False for characters to be deleted 
    preserve = [True] * len(s) 
    for i, j in blocks: 
     preserve[i:j] = False 

    result = [] 
    for i, c in enumerate(s): 
     if preserve[i]: 
      result.append(c) 

    return ''.join(result) 
+0

此代碼未經測試且無法正常工作 –