The Bugs:
- Duplicates: Sorting
[5, 5, 3] yields [3, 5, 5]. xs[-2] returns the second element from the end (5) rather than the second largest distinct value (3).
- Side effects & edge cases:
xs.sort() mutates the caller's list in place, and xs[-2] raises an IndexError if there are fewer than two unique numbers.
The Fix:
Convert the list to a set to remove duplicates, check that at least two unique values exist, and use sorted() to avoid mutating the original list:
def second_largest(xs):
unique = sorted(set(xs))
if len(unique) < 2:
raise ValueError("Need at least two distinct numbers")
return unique[-2]
Now second_largest([5, 5, 3]) deduplicates and sorts to [3, 5], returning 3 while leaving the input list unchanged. (If you want $O(n)$ time instead of $O(n \log n)$, you can track the top two distinct values in a single loop.)