I handle the problem in a slightly different way.
Take for instance this list:
[4, 1, 8, 2, 7, 3, 2, 4, 10, 3]
As I can see so far to other solutions given and yours as well @Kangaroo976, the list is sorted in this way:
[4, 3, 7, 2, 10, 1, 8, 2, 4, 3]
[['LEFT'], ['LEFT'], ['LEFT'], ['LEFT'], ['MAX VAL'], ['RIGHT'], ['RIGHT'], ['RIGHT'], ['RIGHT'], ['RIGHT']]
Instead I picture in a different way, so basically have 2 pipes which are 2 list with Max and min value alternatively, so the same input list with my implementation, I would sort the list in 2 like this:
# MAX # MIN
|| 10 * 1 ||
|| 8 * 2 ||
|| 7 * 2 ||
|| 4 * 3 ||
|| 4 * 3 ||
Then you calculate each 2 index 2 times for each numbers, for so you have groups or clusters as follow:
# MAX # MIN
|| 10 * 1 || (10 -1) + (10-2) + (8-1) + (8-2)
|| 8 * 2 ||
|| 7 * 2 || (7-2) + (7-3) + (4-2) + (4-3)
|| 4 * 3 ||
|| 4 * 3 || (4-3)
In case the list has odds numbers like [4, 1, 8, 2, 7, 3, 2, 4, 10] the calculation is slightly different:
# MAX # MIN
|| 10 * 1 || (10 -1) + (10-2) + (8-1) + (8-2)
|| 8 * 2 ||
|| 7 * 2 || (7-2) + (7-3) + (4-2) + (4-3)
|| 4 * 3 ||
|| * 4 || # Not Counted
First Solution
Note, is sightly slower than your original
def algorithm(input_list):
max_pipe = list()
min_pipe = list()
max_difference = 0
while len(input_list) > 1:
# --------------- Left Side Max Pipe
max_n = input_list.index(max(input_list))
max_pipe.append(input_list.pop(max_n))
# --------------- Right Side Min Pipe
min_n = input_list.index(min(input_list))
min_pipe.append(input_list.pop(min_n))
if input_list:
min_pipe.append(input_list.pop())
max_comparison = len(min_pipe) - 1
counter = 0 # NOTE: Counter reset each 4. Then adds +2 to offset
offset = 0
for max_val in range(max_comparison):
# --------------- Handle Clusters of calculations, which are each 4 steps
if counter == 4:
counter = 0
offset += 2
for comparison in range(2):
diff = max_pipe[max_val] - min_pipe[comparison + offset]
max_difference += diff
counter += 1
if len(min_pipe) % len(max_pipe) == 0: # NOTE: In list is uneven, needs a last comparison with both last values
max_difference += max_pipe[-1] - min_pipe[-1]
return max_difference
Second Solution
Hence Following this logic, and sorting the list before and devide the list in a Divide-and-conquer fashion I come up with this solution:
def algorithm(input_list):
max_difference = 0
# --------------- List Sorting & Setting Up Max And Min Pip
input_list.sort()
half = len(input_list)//2
max_pipe = input_list[half:]
min_pipe = input_list[:half]
# --------------- Loop Utils
total_comparison = len(input_list) - 2
counter = 1
offset = 0
# --------------- Algorithm
for n in range(half//2):
if counter == total_comparison: # The Algorithm can have only a certain and precise amount of calculations
break
comparison = 0
for N in max_pipe[-counter::-1]:
max_difference += N - min_pipe[offset*2]
max_difference += N - min_pipe[offset*2 + 1]
comparison += 1
if comparison == 2: # NOTE: Only 2 Comparison for each couple (Max, Min) num
break
counter += 2
offset += 1
max_difference += max_pipe[0] - min_pipe[-1] # Last calculation left over
return max_difference
Benchmarking
original = min(timeit.Timer(original_).repeat(1, 20))
print(mine)
print(original)
print('==='*15)
print(min(mine, original))
Output
5.1045565999999996 # Mine
5.519946699999999 # Kangaroo976
=============================================
5.1045565999999996