Reputation: 223
I am trying to define a function, merge, which, when given two sorted arrays containing numbers, returns a sorted array of the numbers from both lists.
merge([ 4, 5, 6 ], [ 1, 2, 3, 4 ]) => [ 1, 2, 3, 4, 4, 5, 6 ]
merge([ 4 ], [ 2, 5, 8 ]) => [ 2, 4, 5, 8 ]
merge([ 1, 2, 6 ], []) => [ 1, 2, 6 ]
This is my code:
function merge(arr1, arr2) {
return arr1.concat(arr2).sort(arr1, arr2);
}
While the output is correct, I am told -- from my studies, and its automated tests -- that this code is not in good style. It writes:
Does not handles two arrays of same length.
Doesn't handle shorter first array.
Doesn't handle shorter second array.
What is a better way I can write this code? What should I do better?
Upvotes: 1
Views: 239
Reputation: 56875
Amadan's answer paid attention to the problem constraints and pointed out that this can be written in O(n) time. Essentially, when inputs are both sorted, the algorithm is the "merge" step in a merge sort. This is done in linear time and works in a very simple and pleasing manner: look at the first item of each list and take the smaller of the two until one or both lists are exhausted. Then, tack any remaining elements onto the result array and return it.
The other answers are fine and in good JS style, but are in O(n log n) time and ignore entirely that the arrays are pre-sorted without mention, which is almost certainly not the answer someone asking for this routine would be looking for.
Here's a merge step:
const merge = (a, b) => {
const result = [];
while (a.length && b.length) {
result.push(a[0] < b[0] ? a.shift() : b.shift());
}
return result.concat(a).concat(b);
};
console.log(merge([ 4, 5, 6 ], [ 1, 2, 3, 4 ])); // => [ 1, 2, 3, 4, 4, 5, 6 ]
console.log(merge([ 4 ], [ 2, 5, 8 ])); // => [ 2, 4, 5, 8 ]
console.log(merge([ 1, 2, 6 ], [])); // => [ 1, 2, 6 ]
This can also be done with indexes which preserves the original arrays and is faster, but a little uglier-looking.
Here's a benchmark at JSPerf.
Upvotes: 3
Reputation: 198324
Other answers already give you the literal answer of how to make your code correct. However, it is possibly missing the point. The function that you described is used in building a "merge sort", a very important sorting algorithm, whose major advantage is that it only needs to read the input lists once, sequentially, resulting in complexity of O(N) per pass; this allows it to even sort things that can't fit into the memory. Your code does not do that - it relies on sort
, which is O(N log(N)) each time you invoke your function, and it doesn't utilise the fact that both its inputs are already pre-sorted (which is a key requirement for merge sort).
The merge sort algorithm will take the first element from both lists, then append the smaller one. Then it compares the next element from that list with the other list's first element, and again takes the smaller one. Repeat until one list is exhausted, then append the rest of the surviving list. (You can find a more exhaustive explanation of the merge sort on the Wikipedia page).
Upvotes: 3
Reputation: 5941
Just concat
the arrays and return after applying a simple sort
function:
console.log(merge([4, 5, 6], [1, 2, 3, 4])); //[ 1, 2, 3, 4, 4, 5, 6 ]
console.log(merge([4], [2, 5, 8])); //[ 2, 4, 5, 8 ]
console.log(merge([1, 2, 6], [])); //[ 1, 2, 6]
function merge(a, b) {
return a.concat(b).sort((a, b) => a - b);
}
Upvotes: 1
Reputation: 30360
Your code looks ok, however the way you're using sort
is incorrect.
One way to use sort is to supply a function that compares two values in the array, and returns a number (positive or negative) to dictate the sorting of those values. For more information on sort, see this article
Consider the following changes to your merge method:
function merge(arr1, arr2) {
return arr1.concat(arr2).sort(function(valueA, valueB) { return valueA - valueB; );
}
Upvotes: 3