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?

Asked By: Timur

||

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.

Answered By: YuriC

Why not

new_array = main + insert
new_array.sort()
Answered By: nikitira

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).

Answered By: Riccardo Bucco
Categories: questions Tags: , , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.