0
def findFirstUnique(lst):
    # Write your code here
    for x in lst:
        print ('x is:{} '.format(x))
        lst.remove(x)
        print lst
        if x not in lst:
            return x

print ('final output is : {}'.format(findFirstUnique(lst)))

Apparently it seems to go through for certain cases like this: [9, 2, 3, 2, 6, 6, 9] And for some other cases, the for loop seems to behave so weirdly: [4, 5, 1, 2, 0, 4]

and the output for the second case :

x is:4  [5, 1, 2, 0, 4] 
x is:1 >>> Why is it not picking "5" as the next value?? [5, 2, 0, 4] final output is : 1

I am kinda losing it now that I am not able to understand this for loop! Any help would be appreciated.

4
  • 5
    Do not remove elements from a list you are iterating over. Commented Jun 16, 2020 at 6:22
  • Just try this for loop, you will know why it was happened: l = [1, 2, 3, 4, 5]; for n in l: l.remove(n) Commented Jun 16, 2020 at 6:28
  • @JanChristophTerasa .. am so happy to have found your answers. This is bothering me for a while .. I am kinda so confused why not to use list.remove() or list.pop() while iterating over the list in a for loop form example.. it seems to work for a few scenarios but some end up like above...can u please explain a little more.. and to justify my ask.. I have tried a lot of websites to understand this but not able to conclude Commented Jun 17, 2020 at 5:53
  • @Yang HG.. perfect.. you got me.. but am just not able to see what is going on here with the for loop? Please can u elaborate and save me some hours of time? Commented Jun 17, 2020 at 5:54

4 Answers 4

2

It is a different approach but it will return the first unique in the list

def findFirstUnique(lst):
    for x in lst:
        if lst.count(x) == 1:
            return x
    return None
Sign up to request clarification or add additional context in comments.

2 Comments

You don't need the else part just leave the return None without the else because if the for loop ends without returning result it will return None.
Thanks @AMH that is the answer to solve it but I am more asking about the for loop behavior.. in my code... but appreciate your response.. and list.count is what I ended up implementing in too..
1

This should suffice, it is succinct and fast.

[*filter(lambda x: lst.count(x) == 1, lst)][0]

Data:

lst = [9, 2, 3, 1, 2, 6, 6, 9]

7 Comments

Succinct, yes. As regard fast, I'm not so sure. Using lst.count(x) is presumably faster than an explicit loop, but is still O(n), and it's implictly inside another loop of O(n). If you do a dictionary lookup from counts obtained e.g. using collections.Counter this will be quicker. Also computing the whole list of unique elements only to extract the first might prove to be slower than an explicit loop that you can terminate early once a match is found.
@alaniwi very true. Terminating after first match would presumably be much faster on bigger lists. Given OP's toy lists though it significantly outperforms all other answers including those using collections.Counter and terminating after first match.
Oh I'm sure you're correct about speed with small lists.
Interestingly, it still seems to perform better than collection.Counter with medium sized and large lists.
Now that is interesting. I wonder why. I presume you tried something similar to my other answer when you tested this?
|
1

In terms of speed, any solution which requires looping over the list for each element in order to check the number of counts (whether as an explicit loop or by using lst.count()) is going to scale as O(n^2) in the worst case. If you start by making a dictionary of counts, and then use the dictionary lookup for each item to check its count, then this should be not much worse than O(n). The code to obtain the counts in pure Python is not particularly difficult, but in fact collections.Counter in the standard library will do it for us, so we may as well use that:

from collections import Counter

def findFirstUnique(lst):
    counts = Counter(lst)
    for x in lst:
        if counts[x] == 1:
            return x
    else:
        return None

if __name__ == '__main__':    
    lst = [9,2,3,2,6,6,9]
    print(findFirstUnique(lst))

3 Comments

Perfect. This is the obvious best way to do this, since it is O(n).
thanks @alaniwi.. if library usage is permitted then yes we can use Counter fro collections.
@teju_surya It is not difficult to implement Counter yourself if you need to, but except perhaps for learning purposes you may as well make use of functions in the standard library.
0

The for loop actually iterates the list using the element's index (say i). At the 2nd loop, i=1, lst=[5, 1, 2, 0, 4]. So, the current element is 1, not 5. As a rule, you should not remove or insert any element while iterating.

def findFirstUnique(lst):
    for i, x in enumerate(lst):
        print('x is:{} '.format(x))
        print(lst[:i]+lst[i+1:])
        if x not in lst[:i]+lst[i+1:]:
            return x

print(findFirstUnique([4, 5, 1, 2, 0, 4]))

3 Comments

try this with [4, 4, 2, 0, 1], it will fail. must check prev. values as well
@SơnNinh thanks for your response.. going by what you said.."The for loop actually iterates the list using the element's index (say i)" and so when this is the list: [4, 5, 1, 2, 0, 4] first loop i=0 and x is 4-- > expected second loop i=1 and x should be =5 right ?
@teju_surya no. Because you removed the first 4, the list would be [5, 1, 2, 0, 4] at the 2nd loop.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.