Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Return first non-repeating (unique) symbol in the string. With tests and timeit.
#!/usr/bin/env python
import re
from timeit import timeit
import unittest
UNIQ_RE = re.compile(r'(.)(?=.*?\1)')
TESTS = {
'test': 'e',
'plperl': 'e',
"Speed is the essence of war. Take advantage of the enemy's " \
"unpreparedness; travel by unexpected routes and strike him where " \
"he has taken no precautions. // from Sun Tzu, The Art of War": 'g',
}
TIMEIT_PREPARE = 'from __main__ import TESTS, nonRepeated, first_uniq;' \
'input = TESTS.keys()[2]'
class TestFunctions(unittest.TestCase):
def test_non_repeated(self):
for test, result in TESTS.iteritems():
self.assertEqual(nonRepeated(test), result)
def test_first_uniq(self):
for test, result in TESTS.iteritems():
self.assertEqual(first_uniq(test), result)
def nonRepeated(st):
repeated = dict()
for l in st:
if l in repeated: repeated[l] = 0
else: repeated[l] = 1
for l in st:
if repeated[l]: return l
def first_uniq(text):
reject = set(re.findall(UNIQ_RE, text))
iterator = (c for c in text if c not in reject)
return next(iterator, '')
if __name__ == '__main__':
# unittest.main()
print timeit('nonRepeated(input)', TIMEIT_PREPARE)
print timeit('first_uniq(input)', TIMEIT_PREPARE)
@paulmillr

This comment has been minimized.

Copy link

paulmillr commented Feb 9, 2012

Elegant but not very efficient solution (twice as slower as nonRepeated()):

from collections import Counter, OrderedDict

class OrderedCounter(Counter, OrderedDict):
    pass

def unique(string):
    return (char for char, count in OrderedCounter(string).items() if count == 1)

def first_unique(s):
    return next(unique(s), "")
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.