2016-10-25 33 views
5

ben aşağıdaki gibi python adlarının bir listesi var ki ama onları kaldırmak istemiyorum. Bunun yerine, bu listede bir defadan fazla görünen her ad için, listenin sırasını koruyarak, son ekin adın n-th olduğu, bu adaya bir son ek eklemek istiyorum. Listede 3 adet Carls bulunduğundan, bunları sırasıyla Carl_1, Carl_2 ve Carl_3 olarak değerlendirmek istiyorum. aşağıdaki gibi Yani bu durumda istenen çıktı: Ben listesi üzerinden döngü ve aşağıdaki kodu gibi bir şey ile, örneğin modifiye gerekiyorsa her isim değiştirerek bunu yapabilirsinizEtiketleme çiftleri

names = ['Alice','Bob_1','Carl_1','Dave','Bob_2','Earl','Carl_2','Frank','Carl_3']

.

def mark_duplicates(name_list): 
    output = [] 
    duplicates = {} 
    for name in name_list: 
     if name_list.count(name) = 1: 
      output.append(name) 
     else: 
      if name in duplicates: 
       duplicates['name'] += 1 
      else: 
       duplicates['name'] = 1 
      output.append(name + "_" + str(duplicates['name'])) 
    return output 

Ancak bu bir sürü iş ve ben yapmak çok zor olmamalı şüpheli bir şey için kod satırları bir çok şey var. Ne yapmak istediğimi gerçekleştirmenin daha basit bir yolu var mı? Örneğin, liste anlama veya itertools gibi bir şey gibi bir şey mi kullanıyorsunuz?

+0

Ben makul bir tek satır olduğunu sanmıyorum r, eğer aradığınız şey buysa. Neyse, eğer girdi "[Alice”, "Alice", "Alice_1", "Alice_2"] ise, ne elde etmeyi bekliyorsunuz? – zvone

+0

Teorik olarak, bu tür girdi asla olmaz. Öyle görünüyorsa, sonuçta, sonuçta ortaya çıkacak olan liste '[' Alice_1 ',' Alice_2 ',' Alice_1 ',' Alice_2 '] olacaktır. –

+0

Sormamın sebebi, belki de sonucun aranmasıdır çünkü ['Alice_1', 'Alice_2', 'Alice_3', 'Alice_4'] '(Ne için olduğunu bilmiyorum). Bu tamamen farklı bir algoritma gerektirecektir. – zvone

cevap

8

collections.Counter defter tutma biraz azaltmak yardımcı olabilir:

In [106]: out = [] 

In [107]: fullcount = Counter(names) 

In [108]: nc = Counter() 

In [109]: for n in names: 
    ...:  nc[n] += 1 
    ...:  out.append(n if fullcount[n] == 1 else '{}_{}'.format(n, nc[n])) 
    ...: 

In [110]: out 
Out[110]: 
['Alice', 'Bob_1', 'Carl_1', 'Dave', 'Bob_2', 'Earl', 'Carl_2', 'Frank', 'Carl_3'] 
0

Aşağıdaki kod aradığınız ve comprehensions kullanır şeyi yapmalıdır:

def get_duplicates(names): 
    counts = { k: 0 for k in names } 
    output = [] 
    for name in names: 
     if count[name] == 0: 
      output.append(name) 
      counts[name] += 1 
     else: 
      output.append("{}_{}".format(name, counts[name])) 
      counts[name] += 1 
    return output 

Güncelleme: Ben sabit OP'in aradığı doğru cevap için benim cevabımdaki kodu. En iyi yol değil, ancak başka bir kütüphanenin kullanımını gerektirmiyor ve 1 dict anlama ve 1 döngü kullanıyor.

+0

'sayımlar [name]' str() ' – TemporalWolf

+0

içine sarılması gerekiyor Ben şimdi' format' için değiştirildi düzeltilmelidir inanıyorum. –

+0

Sadece bir kez görünen öğelere bir sayı koyuyor. –

0

Eğer ilk sipariş umurumda değil, bu bu şekilde düşünebilirim:

  • her isim
  • adı yalnızca görünüyorsa, bir liste oluşturun görünür sayısını sayın Bir kez, hiçbir şey eklemeyiz, ancak bir kereden fazla göründüğünde, ikinci ve sonraki görünümlere _1, _2 ... ekler.Tüm için _1, _2 eki eklemek istiyorsa

    Counter: Counter({'Carl': 3, 'Bob': 2, 'Earl': 1, 'Frank': 1, 'Alice': 1, 'Dave': 1}) 
    ['Earl', 'Frank', 'Alice', 'Dave', 'Carl', 'Carl_1', 'Carl_2', 'Bob', 'Bob_1'] 
    

    :

    import collections 
    
    names = ['Alice', 'Bob', 'Carl', 'Dave', 'Bob', 'Earl', 'Carl', 'Frank', 'Carl'] 
    
    counter = collections.Counter(names) 
    print("Counter: %s" % counter) 
    
    result = [] 
    for name, counts in counter.iteritems(): 
        result.append(name) 
        for i in range(1, counts): 
         result.append("%s_%d" % (name, i)) 
    print(result) 
    

    verir:

Bu işi yapmak için bir collections.Counter kullanabilirsiniz anlamına gelir listede birden fazla olayı olan, ancak el değmemiş bir kez gerçekleşen adları bırakan adlar:

import collections 

names = ['Alice', 'Bob', 'Carl', 'Dave', 'Bob', 'Earl', 'Carl', 'Frank', 'Carl'] 

counter = collections.Counter(names) 
print("Counter: %s" % counter) 

result = [] 
for name, counts in counter.iteritems(): 
    if counts == 1: 
     result.append(name) 
    else: 
     for i in range(counts): 
      result.append("%s_%d" % (name, i + 1)) 
print(result) 

verir: Hangi

counts = {} 
def append(name): 
    try: 
     counts[name] += 1 
     return True 
    except: 
     counts[name] = 1 
     return False 

def get_duplicates(): 
    return ['_'.join([name, str(counts[name])]) if append(name) else name for name in names] 

yararı için: bir

Counter: Counter({'Carl': 3, 'Bob': 2, 'Earl': 1, 'Frank': 1, 'Alice': 1, 'Dave': 1}) 
['Earl', 'Frank', 'Alice', 'Dave', 'Carl_1', 'Carl_2', 'Carl_3', 'Bob_1', 'Bob_2'] 
0

['Alice', 'Bob', 'Carl', 'Dave', 'Bob_2', 'Earl', 'Carl_2', 'Frank', 'Carl_3'] durumunda kabul edilebilir bir çıkışı (bir _1 eklendi sahip olmayan ilk insan) daha sonra aşağıdaki öneriyoruz Bu yaklaşım sadece bir kez names üzerinden geçiyorum, bu yüzden daha fazla görünecek olup olmadığını önceden bilmiyorum.


spec karşılamak için, daha ayrıntılı bir değiştirebilir ekleme:

def append(name): 
    if names.count(name) != 1: 
     try: 
      counts[name] += 1 
     except: 
      counts[name] = 1 
     return True 
    else: 
     return False 

beklenen sonucu verir:

['Alice', 'Bob_1', 'Carl_1', 'Dave', 'Bob_2', 'Earl', 'Carl_2', 'Frank', 'Carl_3'] 
0
kullanan

Başka bir çözüm enumerate:

>>> names = ['Alice','Bob','Carl','Dave','Bob','Earl','Carl','Frank','Carl'] 
>>> processed = [] 
>>> for n in names: 
...  if n not in processed: 
...   indices = [i for i,name in enumerate(names) if name == n] 
...   if len(indices) > 1: 
...    suffix = 1 
...    for i in indices: 
...     names[i] = "{}_{}".format(names[i], suffix) 
...     suffix += 1 
...  if n.split('_')[0] not in processed: 
...   processed.append(n) 
... 
>>> 
>>> names 
['Alice', 'Bob_1', 'Carl_1', 'Dave', 'Bob_2', 'Earl', 'Carl_2', 'Frank', 'Carl_3']