I am using Python 3, and trying to detect if an item is the last in a list, but sometimes there will repeats. This is my code:
a = ['hello', 9, 3.14, 9] for item in a: print(item, end='') if item != a[-1]: print(', ')
And I would like this output:
hello, 9, 3.14, 9
But I get this output:
hello, 93.14, 9
I understand why I am getting the output I do not want. I would prefer if I could still use the loop, but I can work around them. (I would like to use this with more complicated code)
So the index of last occurrence of an element in original list is equal to (length_of_list - index_in_reversed_list - 1). You can use the list. reverse() method to reverse the list and then find the index of first occurrence of the required element in reversed list by list. index() method.
Method #1 : Using loop + set() In this, we just insert all the elements in set and then compare each element's existence in actual list. If it's the second occurrence or more, then index is added in result list.
While these answers may work for the specific case of the OP, I found they were unsatisfactory for broader application.
Here are the methods I could think of/saw here and their respective timings.
urlist_len = len(urlist)-1 for x in urlist: if urlist.index(x) == urlist_len: pass
for x in urlist: if x == urlist[-1]: pass
urlist_len = len(urlist)-1 for index, x in enumerate(urlist): if index == urlist_len: pass
Here are some timing for some different methods:
╔════════════════════════════════════════════════════════════════╗ ║ Timing Results (s) ║ ╠═══════════════════════╦════╦═════════╦════════╦═══════╦════════╣ ║ List size ║ 20 ║ 200 ║ 2000 ║ 20000 ║ 200000 ║ ╠═══════════════════════╬════╬═════════╬════════╬═══════╬════════╣ ║ ║ 0 ║ 0.0006 ║ 0.051 ║ 5.2 ║ 560 ║ ║ Index Method ║ ║ ║ ║ ║ ║ ╠═══════════════════════╬════╬═════════╬════════╬═══════╬════════╣ ║ ║ 0 ║ 0 ║ 0.0002 ║ 0.003 ║ 0.034 ║ ║ Negative Slice Method ║ ║ ║ ║ ║ ║ ╠═══════════════════════╬════╬═════════╬════════╬═══════╬════════╣ ║ Enumerate Method ║ 0 ║ 0.00004 ║ 0.0005 ║ 0.016 ║ 0.137 ║ ╚═══════════════════════╩════╩═════════╩════════╩═══════╩════════╝
Note: values <10us rounded to 0
As you can see, the index method is always slower, and it only get exponentially worse as the list size increases. I don't see any reason to use it ever. The Negative slice method is the fastest in all cases, but if you have duplicate items in your list, it will give you a false positive. Also, the negative slice method requires that the sequence you are iterating over supports indexing. So, in the case of duplicate items in your list (or not index supporting sequence) use the fast-but-not-fastest enumerate method.
Edit: as a commentator noted, calculating the length of the list within the loop isn't ideal. I was able to shave 35% off the enumerate method (not reflected in the table at this moment) using this knowledge.
tldr: use negative slice if all elements are unique objects and sequence supports indexing, otherwise enumerate method
Rather than try and detect if you are at the last item, print the comma and newline when printing the next (which only requires detecting if you are at the first):
a = ['hello', 9, 3.14, 9] for i, item in enumerate(a): if i: # print a separator if this isn't the first element print(',') print(item, end='') print() # last newline
The enumerate()
function adds a counter to each element (see What does enumerate mean?), and if i:
is true for all values of the counter except 0
(the first element).
Or use print()
to insert separators:
print(*a, sep=',\n')
The sep
value is inserted between each argument (*a
applies all values in a
as separate arguments, see What does ** (double star) and * (star) do for parameters?). This is more efficient than using print(',n'.join(map(str, a)))
as this doesn't need to build a whole new string object first.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With