-3

Possible Duplicate:
How do you remove duplicates from a list whilst preserving order?

So the idea is the program takes a string of characters and removes the same string with any duplicated character only appearing once -- removing any duplicated copy of a character. So Iowa stays Iowa but the word eventually would become eventually

Cœur
  • 37,241
  • 25
  • 195
  • 267
Slowbro
  • 189
  • 3
  • 13

8 Answers8

3

Here is an inefficient method:

x = 'eventually'
newx = ''.join([c for i,c in enumerate(x) if c not in x[:i]])

I don't think that there is an efficient way to do it in a list comprehension.

Justin Peel
  • 46,722
  • 6
  • 58
  • 80
3

Here it is as an O(n) (average case) generator expression. The others are all roughly O(n2).

chars = set()
string = "aaaaa"
newstring = ''.join(chars.add(char) or char for char in string if char not in chars)

It works because set.add returns None, so the or will always cause the character to be yielded from the generator expression when the character isn't already in the set.

Edit: Also see refaim's solutions. My solution is like his second one, but it uses the set in the opposite way.

My take on his OrderedDict solution:

''.join(OrderedDict((char, None) for char in word))
agf
  • 171,228
  • 44
  • 289
  • 238
  • To be frank, these aren't pure list comprehension solutions (and neither are refaim's) and I'm not saying that because of generator expressions. I'm saying it because they require another line like defining a set or importing OrderedDict. It's not a big deal because this is kind of a stupid question anyway, but I thought that I would point it out. – Justin Peel Oct 13 '11 at 15:31
  • 1
    @JustinPeel See Matt's golfed version of my answer. I could do the same for `OrderedDict` with `__import__`. They're just _more Pythonic_ with another line, they don't _require_ another line. Remember, questions and answers are for all the people who Google this in the future, not just the person asking. That's what makes bad questions like this worth answering to me -- giving an answer better than the naive one that might be useful or interesting to someone in the future. Not following arbitrary restrictions. It's not code golf. "Elegant" has value. One-line for one-line's sake doesn't. – agf Oct 13 '11 at 18:47
2

Without list comprehensions:

from collections import OrderedDict

word = 'eventually'
print ''.join(OrderedDict(zip(word, range(len(word)))).keys())

With list comprehensions (quick and dirty solution):

word = 'eventually'
uniq = set(word)
print ''.join(c for c in word if c in uniq and not uniq.discard(c))
refaim
  • 1,875
  • 1
  • 14
  • 9
  • Nice. I didn't see yours before I posted mine, they're similar. I also added a modified version of your `OrderedDict` method to my answer. Also, it's a generator expression not a list comprehension :) – agf Oct 13 '11 at 03:06
  • Yeah, yours `OrderedDict` method is more fast and accurate than mine. – refaim Oct 13 '11 at 03:10
2
>>> s='eventually'
>>> "".join([c for i,c in enumerate(s) if i==s.find(c)])
'evntualy'

note that using a list comprehension with join() is silly when you can just use a generator expression. You should tell your teacher to update their question

John La Rooy
  • 295,403
  • 53
  • 369
  • 502
0

You could make a set from the string, then join it together again. This works since sets can only contain unique values. The order wont be the same though:

In [1]: myString = "mississippi"

In [2]: set(myString))
Out[2]: set(['i', 'm', 'p', 's'])

In [3]: print "".join(set(myString))
Out[3]: ipsm

In [4]: set("iowa")
Out[4]: set(['a', 'i', 'o', 'w'])

In [5]: set("eventually")
Out[5]: set(['a', 'e', 'l', 'n', 't', 'u', 'v', 'y'])

Edit: Just saw the "List Comprehension" in the title so this probably isnt what your looking for.

chown
  • 51,908
  • 16
  • 134
  • 170
0

Create a set from the original string, and then sort by position of character in original string:

>>> s='eventually'
>>> ''.join(sorted(set(s), key=s.index))
'evntualy'
Austin Marshall
  • 2,991
  • 16
  • 14
0

Taken from this question, I think this is the fastest way:

>>> def remove_dupes(str):
...    chars = set()
...    chars_add = chars.add
...    return ''.join(c for c in str if c not in chars and not chars_add(c))
... 
>>> remove_dupes('hello')
'helo'
>>> remove_dupes('testing')
'tesing'
Community
  • 1
  • 1
jterrace
  • 64,866
  • 22
  • 157
  • 202
0
word = "eventually"
evntualy = ''.join(
     c 
     for d in [dict(zip(word, word))] 
         for c in word 
     if d.pop(c, None) is not None)

Riffing off of agf's (clever) solution but without making a set outside of the generator expression:

evntualy = ''.join(s.add(c) or c for s in [set()] for c in word if c not in s)
Matt Anderson
  • 19,311
  • 11
  • 41
  • 57