l1 = ['A','B','C','D','A','B']
l2 = []
'C' is the first value in list l1, i want to create a function so that it returns C in l2.
l1 = ['A','B','C','D','A','B']
l2 = []
'C' is the first value in list l1, i want to create a function so that it returns C in l2.
In 3.6 and higher, this is very easy. Now that dict
s preserve insertion order, collections.Counter
can be used to efficiently count all elements in a single pass, then you can just scan the resulting Counter
in order to find the first element with a count of 1:
from collections import Counter
l1 = ['A','B','C','D','A','B']
l2 = [next(k for k, v in Counter(l1).items() if v == 1)]
Work is strictly O(n)
, with only one pass of the input required (plus a partial pass of the unique values in the Counter
itself), and the code is incredibly simple. In modern Python, Counter
even has a C accelerator for counting inputs that pushes all the Counter
construction work to the C layer, making it impossible to beat. If you want to account for the possibility that no such element exists, just wrap the l2
initialization to make it:
try:
l2 = [next(k for k, v in Counter(l1).items() if v == 1)]
except StopIteration:
l2 = []
# ... whatever else makes sense for your scenario ...
or avoid exception handling with itertools.islice
(so l2
is 0-1 items, and it still short-circuits once a hit is found):
from itertools import islice
l2 = list(islice((k for k, v in Counter(l1).items() if v == 1), 1))
You can convert list
to string
and then compare index
of each character from left and right using find
and rfind
functions of string. It stops counting as soon as the first match is found,
l1 = ['A','B','C','D','A','B']
def i_list(input):
l1 = ''.join(input)
for i in l1:
if l1.find(i) == l1.rfind(i):
return(i)
print(i_list(l1))
# output
C
An implementation using a defaultdict:
# Initialize
from collections import defaultdict
counts = defaultdict(int)
# Count all occurrences
for item in l1:
counts[item] += 1
# Find the first non-duplicated item
for item in l1:
if counts[item] == 1:
l2 = [item]
break
else:
l2 = []
As a follow up to ShadowRanger's answer, if you're using a lower version of Python, it's not that more complicated to filter the original list so that you don't have to rely on the ordering of the counter items:
from collections import Counter
l1 = ['A','B','C','D','A','B']
c = Counter(l1)
l2 = [x for x in l1 if c[x] == 1][:1]
print(l2) # ['C']
This is also O(n).
We can do it also with "numpy".
def find_first_non_duplicate(l1):
indexes_counts = np.asarray(np.unique(l1, return_counts=True, return_index=True)[1:]).T
(not_duplicates,) = np.where(indexes_counts[:, 1] == 1)
if not_duplicates.size > 0:
return [l1[np.min(indexes_counts[not_duplicates, 0])]]
else:
return []
print(find_first_non_duplicate(l1))
# output
['C']
dict
.Loop through the dict
and check the first element whose count is
def countElement(a):
"""
returns a dict of element and its count
"""
g = {}
for i in a:
if i in g:
g[i] +=1
else:
g[i] =1
return g
#List to be processed - input_list
input_list = [1,1,1,2,2,2,2,3,3,4,5,5,234,23,3,12,3,123,12,31,23,13,2,4,23,42,42,34,234,23,42,34,23,423,42,34,23,423,4,234,23,42,34,23,4,23,423,4,23,4] #Input from user
try:
if input_list: #if list is not empty
print ([i for i,v in countElement(input_list).items() if v == 1][0]) #get the first element whose count is 1
else: #if list is empty
print ("empty list in Input")
except: #if list is empty - IndexError
print (f"Only duplicate values in list - {input_list}")