Still celebrating National IT Professionals Day with 3 months of free Premium Membership. Use Code ITDAY17


How to identify duplicates in a list and update?

Posted on 2014-04-22
Medium Priority
Last Modified: 2014-04-24
Hello all,

I'm trying to figure out how to identify duplicate entries in a list and rename them appropriately so that I have unique names across the list (all while maintaining the same order).  I found a wonderful reference that nearly gets me there:

The actual code looks like this:
from collections import Counter
from string import ascii_uppercase as letters

def gen(L):
    c = Counter(L)
    for elt, count in c.items():
        if count == 1:
            yield elt
            for letter in letters[:count]:
                yield elt + letter

Open in new window

And input/output looks like this:

>>> L = ['T1','T2','T2','T2','T2','T3','T3']
>>> list(gen(L))
['T2A', 'T2B', 'T2C', 'T2D', 'T3A', 'T3B', 'T1']

Open in new window

What I'm trying to understand is why it's re-arranging the order of the list based on number of occurrences (I'm guessing it's doing a LIFO type of list insertion based on the for loop?).  What I would like to do is maintain the original order of the list while these updates are applied.  Has anyone tried anything like this before?  I'm pretty new to Python but I'm getting up to speed pretty quickly and getting to be a fan of the language.  Any help is appreciated!

Thanks in advance,
Question by:jisoo411
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 4
  • 3
LVL 17

Expert Comment

ID: 40016921
dicts are unordered and in the documentation Counter is marked to be a subclass of dict.
So for your exact requirement you might have to roll your own class.

Insteead of giving you an answer I'd like to ask you some questions first, as they are
 important to find the best solution for your exact use case.

will the list always be alphabetically sorted?
If yes, then you could change above code by changing line 6 from
    for elt, count in c.items():

Open in new window

    for elt, count in sorted(c.items()):

Open in new window

If not:
Let s assume
L = ['T2','T2','T3','T2','T2','T1','T3']
Would following output  be satisfying for you?
L = ['T2','T2A','T3','T2B','T2C','T1','T3A']

Open in new window

or do you insist on
L = ['T2A','T2B','T3A','T2C','T2D','T1','T3B']

Open in new window

Could L ever be something like  =
L = ['T2','T2','T3','T2','T2','T1','T3', 'T2A']

Open in new window

How would you like to handle this situation?  (Unification of T2 would result in T2A and this would mean, that T2A would now exist twice.
should the last 'T2A' become 'T2AA'?

Author Comment

ID: 40018455
Hi Gelonida,

Thanks for replying.  To answer your questions, the list could indeed look like:

L = ['T2','T2A','T3','T2B','T2C','T1','T3A']

Open in new window

What matters most is being able to distinguish between the duplicated column names and keep all columns in the same order.  In reference to the last question, I don't think I would see a column name coming in with 'T2A'.  But if it did 'T2AA' or something to distinguish it would work.  

LVL 29

Accepted Solution

pepr earned 1332 total points
ID: 40018744
Try the following function. It can also be converted to generator, but you probably want to insert it to the CSV file or the like:

def make_unique(lst):
    used = set()             # set of the names used earlier
    result = []              # the modified list
    for name in lst:         # check every input name
        if name not in used:
            result.append(name)   # it was not used yet, so left it as is
            used.add(name)        # but it was used now
            # We have to modify the earlier used name. Say to add
            # one of the capital letters. Try from A and check.
            for extension in 'ABCDEFGHIJKLMNOPQRSTUVWXYZ':
                xname = name + extension     # the modified name
                if xname not in used:
                    break                    # this one was not used
            result.append(xname)  # append to the result           
            used.add(xname)       # and remember as used
    return result        

L = ['T1','T2','T2','T2','T2','T3','T3']
LL = make_unique(L)

Open in new window

It prints on my console
['T1', 'T2', 'T2', 'T2', 'T2', 'T3', 'T3']
['T1', 'T2', 'T2A', 'T2B', 'T2C', 'T3', 'T3A']

Open in new window

On Demand Webinar: Networking for the Cloud Era

Ready to improve network connectivity? Watch this webinar to learn how SD-WANs and a one-click instant connect tool can boost provisions, deployment, and management of your cloud connection.

LVL 17

Assisted Solution

gelonida earned 668 total points
ID: 40019577
minor suggestion in order to detect potential (in real world probably non existing)
failures to uniqify your list:

add following after line 16:
            print "failed to uniqify list" 
           raise UniqifyException()

Open in new window

and add following lines to the beginning of the file

class UniqifyException(Exception):
    """ custom exception """"

Open in new window

The code could be sped up slightly if you used a dict with counter values instead of a set, but I think for most real world cases this will not matter and the current code is easier to read.
LVL 29

Assisted Solution

pepr earned 1332 total points
ID: 40019703
Well, in the case that 26 characters would not be enough to solve the duplicates, I would rather change the extension method to generate say the '_1', '_2', ..., '_156', etc.

There cannot be else after the line 16. The problem of repeating say T2Z (i.e. detection of the unsolved case) must be solved after the for loop finished via testing against used set (again). If used, then another extension method could be used - say generating 'AA', 'AB', 'AC', etc.

Even better solution would be to define a generator of the 'A', 'B', ..., 'Z', 'AA', ..., 'AZ', 'BA', etc. sequence instead of the 'ABCD...Z' string.
LVL 17

Expert Comment

ID: 40019718
Perhaps I misread, but I thought python for loops can have an else statement being entered whenever the for loop is completed without having hit a break statement

( )

Checking whether the resulting list is really unique is just a defensive practice without trying to code a fully generic fool proof solution. (I like to code as little as possible, but verify that my result is correct. If I get exceptions I start coding the more complete solution.
Having silently a non unique list causing an error somewhere completely else might be dangerous or difficult to detect)

I prefer an exception to a non unique list or to a potentially too complicated solution.

Your suggestion with an infinite iterator would of course solve the problem.

Instead of the else statement in the for loop one could also check between line 18 and 19 of your original code, that, len(used) == len(result) and if not raise an error.
LVL 29

Expert Comment

ID: 40020575
@gelonida: Oh, I see. Well, I thought you mean the else of the if. The reason is that I am not used to the else clause of the for loop (or of the while loop). It seems strange to me, difficult to understand as it is not used in other programming languages. One have to thing hard what does it mean. I could bet, people would not find how it works without reading a documentation. And even many the people who know it exists have to look to the doc again if they meet the situation again. But you are right...
Errors should never pass silently.
Unless explicitly silenced.
LVL 17

Expert Comment

ID: 40020745
Fully agree, this else syntax is bizarre and probably it's better to avoid it as too many people (sometimes myself included ;-) ) have to look in the doc .

Featured Post

Free Tool: Site Down Detector

Helpful to verify reports of your own downtime, or to double check a downed website you are trying to access.

One of a set of tools we are providing to everyone as a way of saying thank you for being a part of the community.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Here I am using Python IDLE(GUI) to write a simple program and save it, so that we can just execute it in future. Because when we write any program and exit from Python then program that we have written will be lost. So for not losing our program we…
Dictionaries contain key:value pairs. Which means a collection of tuples with an attribute name and an assigned value to it. The semicolon present in between each key and values and attribute with values are delimited with a comma.  In python we can…
Learn the basics of lists in Python. Lists, as their name suggests, are a means for ordering and storing values. : Lists are declared using brackets; for example: t = [1, 2, 3]: Lists may contain a mix of data types; for example: t = ['string', 1, T…
Learn the basics of if, else, and elif statements in Python 2.7. Use "if" statements to test a specified condition.: The structure of an if statement is as follows: (CODE) Use "else" statements to allow the execution of an alternative, if the …

722 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question