tags:

views:

380

answers:

8

i have a list with duplicate elements:

In python:

 list_a=[1,2,3,5,6,7,5,2]

 tmp=[]

 for i in list_a:
     if tmp.__contains__(i):
         print i
     else:
         tmp.append(i)

i have used the above code to found the duplicate elements in the list_a. i dont want to remove the elements form list.

But i want to use for loop here: Normally C/C++ we use like this i guess:

 for (int i=0;i<=list_a.length;i++)
     for (int j=i+1;j<=list_a.length;j++)
         if (list_a[i]==list_a[j])
             print list_a[i]

how do we use like this in Python ?

for i in list_a:
    for j in list_a[1:]:
    ....

i tried the above code .But it gets solution wrong.i dont know how to increase the value for j.pls help...

+5  A: 

Use the in operator instead of calling __contains__ directly.

What you have almost works (but is O(n**2)):

for i in xrange(len(list_a)):
  for j in xrange(i + 1, len(list_a)):
    if list_a[i] == list_a[j]:
      print "duplicate:", list_a[i]

But it's far easier to use a set (roughly O(n) due to the hash table):

seen = set()
for n in list_a:
  if n in seen:
    print "duplicate:", n
  else:
    seen.add(n)

Or a dict, if you want to track locations of duplicates (also O(n)):

import collections
items = collections.defaultdict(list)
for i, item in enumerate(list_a):
  items[item].append(i)
for item, locs in items.iteritems():
  if len(locs) > 1:
    print "duplicates of", item, "at", locs

Or even just detect a duplicate somewhere (also O(n)):

if len(set(list_a)) != len(list_a):
  print "duplicate"
Roger Pate
Why the downvote?
Roger Pate
+1  A: 

If you're looking for one-to-one mapping between your nested loops and Python, this is what you want:

n = len(list_a)
for i in range(n):
    for j in range(i+1, n):
        if list_a[i] == list_a[j]:
            print list_a[i]

The code above is not "Pythonic". I would do it something like this:

seen = set()
for i in list_a:
   if i in seen:
       print i
   else:
       seen.add(i)

Also, don't use __contains__, rather, use in (as above).

Alok
A: 

You could just "translate" it line by line.

c++

for (int i=0;i<=list_a.length;i++)
    for (int j=i+1;j<=list_a.length;j++)
        if (list_a[i]==list_a[j])
            print list_a[i]

Python

for i in range(0, len(list_a)):
    for j in range(i + 1, len(list_a))
        if list_a[i] == list_a[j]:
            print list_a[i]

c++ for loop:

for(int x = start; x < end; ++x)

Python equivalent:

for x in range(start, end):
Fire Lancer
You should not accept this answer. Yes, it's valid code, but it's not the way you should code in Python. Don't code Python like C/C++, or Java. They are not the same languages, and are not meant to be used the same way.
e-satis
I agree with e-satis, although the the question specifically tries to compare the routine to C/C++ we should try to nudge it in the right direction.
mizipzor
+4  A: 

You could always use a list comprehension:

dups = [x for x in list_a if list_a.count(x) > 1]
Evan Fosmark
This traverses the list once for each element (Although, OP's code is O(N**2), too).
Alok
+1 for one-liner
mizipzor
Yeah, I understood it's inefficient. If the OP is looking for that, he should go with Roger's answers for sure.
Evan Fosmark
+2  A: 

The following requires the elements of your list to be hashable (not just implementing __eq__ ). I find it more pythonic to use a defaultdict (and you have the number of repetitions for free):

import collections
l = [1, 2, 4, 1, 3, 3]
d = collections.defaultdict(int)
for x in l:
   d[x] += 1
print [k for k, v in d.iteritems() if v > 1]
# prints [1, 3]
LeMiz
Change to `if d[v] > 1` and I'll +1.
Chris Lutz
Chris: I think you've misunderstood this answer, it works as it is now and your suggestion would break it.
Roger Pate
+5  A: 

Just for information, In python 2.7+, we can use Counter

import collections

x=[1, 2, 3, 5, 6, 7, 5, 2]

>>> x
[1, 2, 3, 5, 6, 7, 5, 2]

>>> y=collections.Counter(x)
>>> y
Counter({2: 2, 5: 2, 1: 1, 3: 1, 6: 1, 7: 1})

Unique List

>>> list(y)
[1, 2, 3, 5, 6, 7]

Items found more than 1 time

>>> [i for i in y if y[i]>1]
[2, 5]

Items found only one time

>>> [i for i in y if y[i]==1]
[1, 3, 6, 7]
S.Mark
+1, definitely pythonic.
LeMiz
`[n for n, i in y.iteritems() if i > 1]` instead, and `i == 1`.
Roger Pate
...but why the list(y), isn't Counter iterable ?
LeMiz
You're right LeMiz, I was a bit rush. Thanks
S.Mark
@Roger Pate, thanks, yours is no need to do dict lookup, it could be better.
S.Mark
A: 

A little bit more Pythonic implementation (not the most, of course), but in the spirit of your C code could be:

for i, elem in enumerate(seq):
    if elem in seq[i+1:]:
        print elem

Edit: yes, it prints the elements more than once if there're more than 2 repetitions, but that's what the op's C pseudo code does too.

fortran
You must sort before doing that. Use sorted. What's more, you will print the same duplicate several times if there is more than one of the same.
e-satis
This will print the same element multiple times if it occurs more than 2 times in the list.
truppo
Have you guys bothered to read the op's code? It does the exactly the same. @e-satis There's no need to sort, maybe you meant something like `[k for k, it in itertools.groupby(sorted(l)) if len(list(it)) > 1]` ?
fortran
+3  A: 

Before Python 2.3, use dict() :

>>> lst = [1, 2, 3, 5, 6, 7, 5, 2]
>>> stats = {}
>>> for x in lst : # count occurrences of each letter:
...     stats[x] = stats.get(x, 0) + 1 
>>> print stats
{1: 1, 2: 2, 3: 1, 5: 2, 6: 1, 7: 1} # filter letters appearing more than once:
>>> duplicates = [dup for (dup, i) in stats.items() if i > 1] 
>>> print duplicates

So a function :

def getDuplicates(iterable):
    """
       Take an iterable and return a generator yielding its duplicate items.
       Items must be hashable.

       e.g :

       >>> sorted(list(getDuplicates([1, 2, 3, 5, 6, 7, 5, 2])))
       [2, 5]
    """
    stats = {}
    for x in iterable : 
        stats[x] = stats.get(x, 0) + 1
    return (dup for (dup, i) in stats.items() if i > 1)

With Python 2.3 comes set(), and it's even a built-in after than :

def getDuplicates(iterable):
    """
       Take an iterable and return a generator yielding its duplicate items.
       Items must be hashable.

       e.g :

       >>> sorted(list(getDuplicates([1, 2, 3, 5, 6, 7, 5, 2])))
       [2, 5]
    """
    try: # try using built-in set
        found = set() 
    except NameError: # fallback on the sets module
        from sets import Set
        found = Set()

    for x in iterable:
        if x in found : # set is a collection that can't contain duplicate
            yield x
        found.add(x) # duplicate won't be added anyway

With Python 2.7 and above, you have the collections module providing the very same function than the dict one, and we can make it shorter (and faster, it's probably C under the hood) than solution 1 :

import collections

def getDuplicates(iterable):
    """
       Take an iterable and return a generator yielding its duplicate items.
       Items must be hashable.

       e.g :

       >>> sorted(list(getDuplicates([1, 2, 3, 5, 6, 7, 5, 2])))
       [2, 5]
    """
    return (dup for (dup, i) in collections.counter(iterable).items() if i > 1)

I'd stick with solution 2.

e-satis