insert an array into main array
Question:
I have a function insarrintomain which takes 2 arguments. The first one is main list, the second one is an insert list. I need to create a new list, where I will have all numbers from both arrays in increasing order. For example: main is [1, 2, 3, 4, 8, 9, 12]
, ins is [5, 6, 7, 10]
. I should get [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 12]
Here is my code:
def insarrintomain(main, ins):
arr = []
c = 0
for i, el in enumerate(main):
if c < len(ins):
if el > ins[c]:
for j, ins_el in enumerate(ins):
if ins_el < el:
c += 1
arr.append(ins_el)
else:
break
else:
arr.append(el)
else:
arr.append(el)
return arr
What did I miss?
Answers:
The pyhonic way of solving this problem is something like this:
def insarrintomain(main, ins):
new_list = main + ins
new_list.sort()
return new_list
In Python readability counts.
This code is pythonic because it’s easy to read: the function takes two lists, concatenates them into one new list, sorts the result and returns it.
Another reason why this code is pythonic is because it uses built-in functions. There is no need to reinvent the wheel: someone already needed to concatenate two lists, or to sort one. Built-in functions such as sort
have been optimised for decades and are mostly written in C language. By no chance we can beat them using Python.
Let’s analyse the implementation from @RiccardoBucco.
That is perfect C code. You barely can understand what is happening without comments. The algorithm is the best possible for our case (it exploits the existing ordering of the lists) and if you can find in the standard libraries an implementation of that algorithm you should substitute sort
with that.
But this is Python, not C. Solving your problem from scratch and not by using built-ins results in an uglier and slower solution.
You can have a proof of that by running the following script and watching how many time each implementation needs
import time
long_list = [x for x in range(100000)]
def insarrintomain(main, ins):
# insert here the code you want to test
return new_list
start = time.perf_counter()
_ = insarrintomain(long_list, long_list)
stop = time.perf_counter()
print(stop - start)
On my computer my implementation took nearly 0.003 seconds, while the C-style implementation from @RiccardoBucco needed 0.055 seconds.
Why not
new_array = main + insert
new_array.sort()
A simple solution would be:
def insarrintomain(main, ins):
return (main + ins).sorted()
But this solution is clearly not optimal (the complexity is high, as we are not using the fact that the input arrays are already sorted). Specifically, the complexity here is O(k * log(k)), where k is the sum of n and m (n is the length of main
and m is the length of ins
).
A better solution:
def insarrintomain(main, ins):
i = j = 0
arr = []
while i < len(main) and j < len(ins):
if main[i] < ins[j]:
arr.append(main[i])
i += 1
else:
arr.append(ins[j])
j += 1
while i < len(main):
arr.append(main[i])
i += 1
while j < len(ins):
arr.append(ins[j])
j += 1
return arr
Example:
>>> insarrintomain([1, 2, 3, 4, 8, 9, 12], [5, 6, 7, 10])
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 12]
This solution is much faster for big arrays (O(k), where k is the sum of n and m, n is the length of main
and m is the length of ins
).
I have a function insarrintomain which takes 2 arguments. The first one is main list, the second one is an insert list. I need to create a new list, where I will have all numbers from both arrays in increasing order. For example: main is [1, 2, 3, 4, 8, 9, 12]
, ins is [5, 6, 7, 10]
. I should get [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 12]
Here is my code:
def insarrintomain(main, ins):
arr = []
c = 0
for i, el in enumerate(main):
if c < len(ins):
if el > ins[c]:
for j, ins_el in enumerate(ins):
if ins_el < el:
c += 1
arr.append(ins_el)
else:
break
else:
arr.append(el)
else:
arr.append(el)
return arr
What did I miss?
The pyhonic way of solving this problem is something like this:
def insarrintomain(main, ins):
new_list = main + ins
new_list.sort()
return new_list
In Python readability counts.
This code is pythonic because it’s easy to read: the function takes two lists, concatenates them into one new list, sorts the result and returns it.
Another reason why this code is pythonic is because it uses built-in functions. There is no need to reinvent the wheel: someone already needed to concatenate two lists, or to sort one. Built-in functions such as sort
have been optimised for decades and are mostly written in C language. By no chance we can beat them using Python.
Let’s analyse the implementation from @RiccardoBucco.
That is perfect C code. You barely can understand what is happening without comments. The algorithm is the best possible for our case (it exploits the existing ordering of the lists) and if you can find in the standard libraries an implementation of that algorithm you should substitute sort
with that.
But this is Python, not C. Solving your problem from scratch and not by using built-ins results in an uglier and slower solution.
You can have a proof of that by running the following script and watching how many time each implementation needs
import time
long_list = [x for x in range(100000)]
def insarrintomain(main, ins):
# insert here the code you want to test
return new_list
start = time.perf_counter()
_ = insarrintomain(long_list, long_list)
stop = time.perf_counter()
print(stop - start)
On my computer my implementation took nearly 0.003 seconds, while the C-style implementation from @RiccardoBucco needed 0.055 seconds.
Why not
new_array = main + insert
new_array.sort()
A simple solution would be:
def insarrintomain(main, ins):
return (main + ins).sorted()
But this solution is clearly not optimal (the complexity is high, as we are not using the fact that the input arrays are already sorted). Specifically, the complexity here is O(k * log(k)), where k is the sum of n and m (n is the length of main
and m is the length of ins
).
A better solution:
def insarrintomain(main, ins):
i = j = 0
arr = []
while i < len(main) and j < len(ins):
if main[i] < ins[j]:
arr.append(main[i])
i += 1
else:
arr.append(ins[j])
j += 1
while i < len(main):
arr.append(main[i])
i += 1
while j < len(ins):
arr.append(ins[j])
j += 1
return arr
Example:
>>> insarrintomain([1, 2, 3, 4, 8, 9, 12], [5, 6, 7, 10])
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 12]
This solution is much faster for big arrays (O(k), where k is the sum of n and m, n is the length of main
and m is the length of ins
).