2013-06-05 95 views
2

我有一個數組,其中包含重複的字符串。我想查找並替換這些字符串,但是每次匹配時我都想要更改替換字符串的值。查找並替換Array中的重複項,但用不同的字符串替換每個第n個實例

讓我來演示一下。

該樣品陣列:

SampleArray = ['champ', 'king', 'king', 'mak', 'mak', 'mak'] 

應該得到改變:

SampleArray = ['champ', 'king1', 'king2', 'mak1', 'mak2', 'mak3'] 

如何實現這一目標?我現在已經有3天沒有運氣了。提前致謝。

My Failed Code: 

import os, collections, re 

SampleArray = ['champ', 'king', 'king', 'mak', 'mak', 'mak'] 
dupes = [x for x, y in collections.Counter(SampleArray).items() if y > 1] 
length = len(dupes) 
count = 0 

while count < length: 
    j = 0 
    instances = SampleArray.count(dupes[count]) 
    while j < instances: 
     re.sub(dupes[count], dupes[count] + j, SampleArray, j) 
     j += 1 
    count += 1 
print SampleArray  
print ''; os.system('pause') 
+1

不應該把champ變成champ1嗎? – Emmanuel

+0

不重複,只有國王和麥克重複 – KingMak

+0

結果列表的項目順序是否重要? –

回答

5

我會使用collections.Counter:

from collections import Counter 

numbers = { 
    word: iter([""] if count == 1 else xrange(1, count + 1)) 
    for word, count in Counter(sample).items() 
} 

result = [ 
    word + str(next(numbers[word])) 
    for word in sample 
] 

這不要求列表以任何方式排序或分組。

該解決方案使用iterators生成序列號:

  • 第一,我們計算了多少次列表(Counter(sample))發生的每個字。

  • 然後我們創建了一個字典numbers,其中,每個字,包含了它的「編號」迭代iter(...)。如果這個詞只出現一次count==1,這個迭代器將返回(「yield」)一個空字符串,否則它將產生範圍從1到[""] if count == 1 else xrange(1, count + 1)的連續數字。

  • 最後,我們再次迭代列表,並且對於每個單詞,從它自己的編號迭代器next(numbers[word])中選擇下一個值。由於我們的迭代器返回數字,我們必須將它們轉換爲字符串str(...)

+0

我選擇了這個答案,因爲它不會更改列表順序,還會在列表中添加更正的替換字符串。謝謝thg435 – KingMak

+0

也可以thg435解釋一下你的代碼,這有點凌駕於我的頭上 – KingMak

+1

@Ahmed:我已經重新格式化了代碼並添加了一些解釋。 – georg

0

編輯

計數器和比排序更簡單:

L = ['champ', 'king', 'king', 'mak', 'mak', 'mak'] 
counts = Counter(L) 
res = [] 
for word in sorted(counts.keys()): 
    if counts[word] == 1: 
     res.append(word) 
    else: 
     res.extend(['{}{}'.format(word, index) for index in 
        range(1, counts[word] + 1)]) 

所以這

['champ', 'mak', 'king', 'king', 'mak', 'mak'] 

也給:

['champ', 'king1', 'king2', 'mak1', 'mak2', 'mak3'] 
+0

你作弊。冠軍不會被替換,因爲您先追加它,而不是因爲它只有一次迭代。 – njzk2

0

一種方法是你的數組轉換成那樣的詞典:

SampleDict = {} 
for key in SampleArray: 
    if key in SampleDict: 
     SampleDict[key][0] = True # means: duplicates 
     SampleDict[key][1] += 1 
    else: 
     SampleDict[key] = [False, 1] # means: no duplicates 

現在你可以很容易地轉換該字典回陣列。然而,如果在SampleArray的順序是非常重要的,那麼你可以做這樣的:

for i in range(len(SampleArray)): 
    key = SampleArray[i] 
    counter = SampleDict[key] 
    if index[0]: 
     SampleArray[i] = key + str(counter[1]) 
    counter[1] -= 1 

然而,這將讓你相反的順序,即

SampleArray = ['champ', 'king2', 'king1', 'mak3', 'mak2', 'mak1'] 

但我敢肯定你會能夠調整它以滿足您的需求。

+0

但爲什麼它只是冠軍而不是冠軍? – KingMak

+0

@Ahmed對,我已經更新了答案。 – freakish

+0

嗯,這真的很好,但順序問題,它不能被顛倒,只是放在前面和國王(S)在最後,所以我會等待更好的答案,如果不是那麼我會接受 – KingMak

2

groupby是一種方便的方式來組重複:

>>> from itertools import groupby 
>>> FinalArray = [] 
>>> for k, g in groupby(SampleArray): 
    # g is an iterator, so get a list of it for further handling 
    items = list(g) 
    # If only one item, add it unchanged 
    if len(items) == 1: 
     FinalArray.append(k) 
    # Else add index at the end 
    else: 
     FinalArray.extend([j + str(i) for i, j in enumerate(items, 1)]) 


>>> FinalArray 
['champ', 'king1', 'king2', 'mak1', 'mak2', 'mak3'] 
+0

+1不改變初始數組的順序 – njzk2

+2

'itertools.groupby'只對連續的項目進行分組,不是嗎? –

+0

好評:只有重複連續時纔有效。 – Emmanuel

0

假設你想要的數組排序:

import collections  
counter = collections.Counter(SampleArray) 
res = [] 
for key in sorted(counter.keys()): 
    if counter[key] == 1: 
     res.append(key) 
    else: 
     res.extend([key+str(i) for i in range(1, counter[key]+1)]) 

>>> res 
['champ', 'king1', 'king2', 'mak1', 'mak2', 'mak3'] 
相關問題