A similar answer as kreativitea above, but with additional information (I think!)
Profiling actual merge functions to merge two 50K arrays,
merge 1
311748 function calls in 15.363 seconds Ordered by: standard name ncalls tottime percall cumtime percall filename:lineno(function) 1 0.001 0.001 15.363 15.363 <string>:1(<module>) 1 15.322 15.322 15.362 15.362 merge.py:3(merge1) 221309 0.030 0.000 0.030 0.000 {len} 90436 0.010 0.000 0.010 0.000 {method 'append' of 'list' objects} 1 0.000 0.000 0.000 0.000 {method 'disable' of '_lsprof.Profiler' objects}
merge2
250004 function calls in 0.104 seconds Ordered by: standard name ncalls tottime percall cumtime percall filename:lineno(function) 1 0.001 0.001 0.104 0.104 <string>:1(<module>) 1 0.074 0.074 0.103 0.103 merge.py:20(merge2) 50000 0.005 0.000 0.005 0.000 {len} 100000 0.010 0.000 0.010 0.000 {method 'append' of 'list' objects} 1 0.000 0.000 0.000 0.000 {method 'disable' of '_lsprof.Profiler' objects} 100000 0.014 0.000 0.014 0.000 {method 'pop' of 'list' objects} 1 0.000 0.000 0.000 0.000 {method 'reverse' of 'list' objects}
So, for merge1 it is 221309 len , 90436 append and takes 15.363 seconds. Therefore, for merge2 it is 50,000 len , 100,000 append and 100000 pop and takes 0.104 seconds.
len and append pop are all O (1) (more info here ), so these profiles donβt show what actually takes time, since this is what happens, it should be faster, but only ~ 20%.
Well, the reason is actually pretty obvious if you just read the code:
The first method has a line like this:
inv += len(left[i:])
therefore, every time it is called, it must rebuild the array. If you comment out this line (or just replace it with inv += 1 or something else), it will become faster than another method. This is the only line responsible for increasing the time.
Having noticed that this is the reason, the problem can be fixed by improving the code; change it to this for speed. After that it will be faster than merge2
inv += len(left) - i
Update it to this:
def merge3(left, right): i = j = inv = 0 merged = [] while i < len(left) and j < len(right): if left[i] <= right[j]: merged.append(left[i]) i += 1 else: merged.append(right[j]) j += 1 inv += len(left) - i merged += left[i:] merged += right[j:] return merged, inv