The soft spot in my previous solution was the combined sorting of the buffer counter dictionary added to a call to index() on the data list. I could live with the sorting, but I felt as unbearable the re-scan the data list to get the actual index. The Counter object knew it on its initialization, why don't use it at that time?
The refactoring ends up with code that is less readable than the first version and the performance gain, in this specific problem is minimal. It would make sense if the problem would require to accept in input long sequences of numbers. Anyway, here it is.
NOT_FOUND = 0 # 1 FOUND_MANY = -1 def solution(line): data = [int(x) for x in line.split()] # 2 result = [0] * 9 # 3 for i, number in enumerate(data): # 4 result[number-1] = i+1 if result[number-1] == NOT_FOUND else FOUND_MANY # 5 for index in result: # 6 if index > NOT_FOUND: return index return 01. I am going to flag the items in the buffer with zero to mean that the relative number was not found, and with a minus one when multiple instance were found.
2. As in the original solution, I convert the input string in a list of integers.
3. Instead of using a Counter collection, here I have a list of integers, reporting for each number in [1..9] the first reference index in data.
4. First loop. I scan each element in data. I need both its position and value, so I use the enumerate builtin to get them.
5. The need for switch from 0-based to 1-based indices leads to this painful line. I have to decrease number, to make it a 0-based index in the buffer list named result, and I have to increase i so that it becomes an 1-based index, as required by the problem.
6. Second loop. I scan each index as stored in the result buffer, as soon as I find a valid value I return it as a solution. If there is no valid index in that list, zero is returned instead.
I pushed the changes on GitHub.