How to merge an array with another one - javascript

I have a challenge to complete where I'm given an array [-1,4,-3,5,6,9,-2] and I need to get a new array that sorts the numbers in this order: [firstGreatest, firstLowest, secondGreatest, secondLowest ...and so on]. The negative and positive numbers may be different amount, as in 4 positive, 2 negative.
This is what I tried so far, but cannot think of a better solution.
let arr = [-1, 2, -5, 3, 4, -2, 6];
function someArray(ary) {
const sorted = ary.sort((a, b) => a - b)
const highest = sorted.filter(num => num > 0).sort((a, b) => b - a)
const lowest = sorted.filter(num => num < 0).sort((a, b) => b - a)
let copy = highest
for (let i = 0; i < highest.length; i++) {
for (let j = i; j < lowest.length; j++) {
if ([i] % 2 !== 0) {
copy.splice(1, 0, lowest[j])
}
}
}
}
console.log(arr)
someArray(arr)
console.log(arr)

You can easily solve this problem with two pointers algorithm.
O(n log n) for sorting
O(n) for add the value in result.
Take two-variable i and j,
i points to the beginning of the sorted array
j points to the end of the sorted array
Now just add the value of the sorted array alternatively in final result
let arr = [-1, 2, -5, 3, 4, -2, 6];
function someArray(ary) {
const sorted = arr.sort((a, b) => b - a);
// declaration
const result = [];
let i = 0,
j = sorted.length - 1,
temp = true;
// Algorithm
while (i <= j) {
if (temp) {
result.push(sorted[i]);
i++;
} else {
result.push(sorted[j]);
j--;
}
temp = !temp;
}
return result;
}
console.log(someArray(arr));
.as-console-wrapper { max-height: 100% !important; top: 0; }

You could sort the array and pop or shift until you have no more items.
function greatestLowest(array) {
let temp = [...array].sort((a, b) => a - b),
m = 'shift',
result = [];
while (temp.length) result.push(temp[m = { pop: 'shift', shift: 'pop' }[m]]());
return result;
}
console.log(...greatestLowest([-1, 2, -5, 3, 4, -2, 6]));

The general idea is to sort the array (highest to lowest) then pick the first and the last element until the array is empty. One way of doing it could be:
const input = [-1, 2, -5, 3, 4, -2, 6];
function someArray(arr) {
// sort the original array from highest to lowest
const sorted = arr.sort((a, b) => b - a);
const output = []
while (sorted.length > 0) {
// remove the first element of the sorted array and push it into the output
output.push(...sorted.splice(0, 1));
// [check to handle arrays with an odd number of items]
// if the sorted array still contains items
// remove also the last element of the sorted array and push it into the output
if (sorted.length > 0) output.push(...sorted.splice(sorted.length - 1, 1))
}
return output;
}
// test
console.log(`input: [${input.join(',')}]`);
console.log(`input (sorted desc): [${input.sort((a, b) => b - a).join(',')}]`)
console.log(`output: [${someArray(input).join(',')}]`);

This is a simple and a shorter method:
function makearray(ar) {
ar = points.sort(function(a, b) {
return b - a
})
let newarray = []
let length = ar.length
for (let i = 0; i < length; i++) {
if (i % 2 == 0) {
newarray.push(ar[0])
ar.splice(0, 1)
} else {
newarray.push(ar[ar.length - 1])
ar.splice(ar.length - 1, 1)
}
}
return newarray
}
const points = [-1, 2, -5, 3, 4, -2, 6]
console.log(makearray(points))

Related

Sum of to arrays with different array sizes

I'm trying to solve sum of to array problem:
//[1,2,3] + [1,2] should be [1,3,5]
I'm able to solve this if the array are the same size, but how can I deal with different array sizes?
Here is my code for now:
function sumOfArrays(a, b) {
let result = new Array(Math.max(a.length, b.length));
let carry = 0;
for (let i = result.length - 1; i >= 0; i--) {
const elementA = a[i];
const elementB = b[i];
const additionResult = elementA + elementB + carry;
result[i] = (additionResult % 10);
carry = Math.floor(additionResult / 10);
}
}
I'm basically getting null values into the result array If there is a difference in the size of the array
You could add a comparison if the 2 arrays are the same length.
If not, you can 'pad' it from the beginning with 0's until ther are the same length.
Then your code will work as expected (after adding return result ;) )
const pad = (arr, size, fill = 0) => [ ...Array(size - arr.length).fill(0), ...arr ];
let a = [1,2,3];
let b = [1,2];
if (a.length < b.length) {
a = pad(a, b.length);
} else if (b.length < a.length) {
b = pad(b, a.length);
}
function sumOfArrays(a, b) {
let result = new Array(Math.max(a.length, b.length));
let carry = 0;
for (let i = result.length - 1; i >= 0; i--) {
const elementA = a[i];
const elementB = b[i];
const additionResult = elementA + elementB + carry;
result[i] = (additionResult % 10);
carry = Math.floor(additionResult / 10);
}
return result;
}
const res = sumOfArrays(a, b);
console.log(res)
However, since the array's are now the same length, we can simplefy the code a lot by using map() and add (+) to current value of the other array on that index:
const pad = (arr, size, fill = 0) => [ ...Array(size - arr.length).fill(0), ...arr ];
let a = [1,2,3];
let b = [1,2];
if (a.length < b.length) {
a = pad(a, b.length);
} else if (b.length < a.length) {
b = pad(b, a.length);
}
function sumOfArrays(a, b) {
return a.map((n, i) => n + b[i]);
}
const res = sumOfArrays(a, b);
console.log(res)
// [
// 1,
// 3,
// 5
// ]
You could take an offset for the index to add.
function add(a, b) {
const
length = Math.max(a.length, b.length),
offsetA = a.length - length,
offsetB = b.length - length;
return Array.from(
{ length },
(_, i) => (a[i + offsetA] || 0) + (b[i + offsetB] || 0)
);
}
console.log(...add([1, 2, 3], [1, 2])); // [1, 3, 5]
console.log(...add([1, 2, 3], [4, 5, 6]));
console.log(...add([1, 2, 3, 4], [1])); // [1, 2, 3, 5]
console.log(...add([1], [1, 2, 3, 4])); // [1, 2, 3, 5]

Maintain the duplicates in the sum of array integers

I wrote a program to:
Print the new array of elements
Print the sum of all elements (or integers)
Actually, I got it right, however, the little problem is, I want to maintain all the duplicates (still within the range of four largest elements). Here's what I mean:
Take an array of numbers: [4,5,-2,3,1,2,6,6]
The four largest numbers are 4,5,6,6. And their sum is 4+5+6+6=21
What the code is doing (not good):
Instead of getting "6,6,5,4" as (described above), the code is printing "6,5,4,3" with the sum as 18.
ALSO, when there are only four elements [with or without duplicates] as in [1,1,1,-5],
let it just add ALL elements. You guessed it, the sum of all elements is -2
How do I order the program to print the necessary duplicate(s) to make the four largest integers?
Here's my code...
var arr = new Array(4,5,-2,3,1,2,6,6);
// var arr = new Array(1,1,1,-5);
// var largArr = new Array();
function largest() {
largArr = Array(0, 0, 0, 0)
for (i = 0; i < arr.length; i++) {
if (arr[i] > largArr[0]) {
largArr[0] = arr[i];
}
}
for (i = 0; i < arr.length; i++) {
if (arr[i] > largArr[1] && arr[i] < largArr[0]) {
largArr[1] = arr[i];
}
}
for (i = 0; i < arr.length; i++) {
if (arr[i] > largArr[2] && arr[i] < largArr[1]) {
largArr[2] = arr[i];
}
}
for (i = 0; i < arr.length; i++) {
if (arr[i] > largArr[3] && arr[i] < largArr[2]) {
largArr[3] = arr[i];
}
}
console.log(largArr[0], largArr[1], largArr[2], largArr[3]);
console.log(largArr[0] + largArr[1] + largArr[2] + largArr[3]);
}
largest();
I believe there is a genius out there who can help me solve this :)
You could get the top four and filter the original array.
function get4Largest(array) {
const top4 = [...array].sort((a, b) => b - a).slice(0, 4);
return array.filter(v => {
if (top4.includes(v)) {
top4.splice(top4.indexOf(v), 1);
return true;
}
});
}
console.log(get4Largest([4, 5, -2, 3, 1, 2, 6, 6]));
A different approach by keeping indices.
function get4Largest(array) {
return array
.map((v, i) => [v, i])
.sort(([a], [b]) => b - a)
.slice(0, 4)
.sort(([, a], [, b]) => a - b)
.map(([v]) => v);
}
console.log(get4Largest([4, 5, -2, 3, 1, 2, 6, 6]));
If you want sum of largest four numbers then you can easily do with sort, slice and reduce:
numbers.sort((a, b) => b - a).slice(0, 4).reduce((acc, curr) => acc + curr, 0)
const numbers = [4, 5, -2, 3, 1, 2, 6, 6];
const result = numbers
.sort((a, b) => b - a)
.slice(0, 4)
.reduce((acc, curr) => acc + curr, 0);
console.log(result);
You can use a reduce, sort and slice methods of an array like so:
function sumMaxValues (maxLength, values) {
return values
.sort((v1, v2) => v1 > v2 ? -1 : 1)
.slice(0, maxLength)
.reduce((sum, v) => sum + v, 0)
}
console.log(
sumMaxValues(4, [4, 5, -2, 3, 1, 2, 6, 6, 10]),
)
Edit: I fixed, a bug that #gog pointed out. The root cause of a problem was that sort when invoked without a compareFn then "the array elements are converted to strings, then sorted according to each character's Unicode code point value."(sort docs)
If for some reason you want to have a classical type of solution, that avoids modern javascript methods, here's one
const arr = Array(4, 5, -2, 3, 1, 2, 6, 6);
//const arr = Array(1, 1, 1, -5);
function largest(){
const largArr = Array(-1/0, -1/0, -1/0, -1/0);
for(let i = 0; i < arr.length; i++){
for(let j = 0; j < largArr.length; j++){
if(arr[i] > largArr[j]){
for(let k = largArr.length - 2; k >= j; k--){
largArr[k + 1] = largArr[k];
}
largArr[j] = arr[i];
break;
}
}
}
let sum = 0;
for(let j = 0; j < largArr.length; j++){
if(largArr[j] === -1/0){
largArr[j] = 0;
}
sum += largArr[j];
}
console.log(largArr, sum);
}
largest();
-1/0 stands for minus infinity (there can be no smaller number); you may also use Number.NEGATIVE_INFINITY for it. If it's too exotic for your needs, replace -1/0 with any number you are certain is less than any possible number in the array (that however, cannot be zero, since you allow negative numbers also).

How to modify array under condition without copying, code should not use any extra space and should be as efficient as possible?

I'm trying to modify array elements under a condition, and then remove duplicates.
Here's my code:
let arr = [2, 3, 4, 1];
arr = arr.map(item => item > 2 ? 0 : item); // zero elements larger than 2
arr = Array.from(new Set(arr)); // remove duplicates
console.log(arr);
Result:
[2, 0, 1]
Although this works, it is copying the modified array which I think is not ideal.
Is there a way to make the code more elegant and performant?
If you don't wanna use any extra space and mutate the same array.
let arr = [2, 3, 4, 1, 1, 1, 1];
for (let i in arr) {
if (arr[i] > 2) {
arr[i] = 0;
}
}
arr = arr.sort();
for (let i = 0; i < arr.length; i++) {
let j = i;
while (arr[j] == arr[j + 1]) {
arr.splice(j, 1);
}
}
console.log(arr);
You can try reduce. Here's an example, which is not elegant, but gets the job done:
let arr = [2, 3, 4, 1];
let add_zero = false;
const out = arr.reduce((s, i) => {
if (i <= 2) {
s.add(i);
} else if (!add_zero) {
add_zero = true;
}
return s;
}, new Set());
if (add_zero) {
out.add(0);
}
console.log(out);

Sort Array to 1st min, 1st max, 2nd min, 2nd max, etc

Write a JS program to return an array in such a way that the first element is the first minimum and the second element is the first maximum and so on.
This program contains a function which takes one argument: an array. This function returns the array according to the requirement.
Sample Input: array=[2,4,7,1,3,8,9]. Expected Output: [1,9,2,8,3,7,4].
const arrsort=(arr)=>{
return arr.sort(function(a, b){return a - b});
}
const test=(arr)=>{
arr=arrsort(arr);
var arr2=[];
var j=0;
var k=arr.length-1;
for (var i=0;i<arr.length-1;i++){
if(i%2===0){
arr2.push(arr[j]);
j++;
}
else{
arr2.push(arr[k]);
k--;
}
}
return arr2;
}
Instead of using two indices, you could shift and pop the values of a copy of the sorted array.
var array = [2, 4, 7, 1, 3, 8, 9]
const arrsort = arr => arr.sort((a, b) => a - b);
const test = (arr) => {
var copy = arrsort(arr.slice()),
result = [],
fn = 'pop';
while (copy.length) {
fn = { pop: 'shift', shift: 'pop' }[fn];
result.push(copy[fn]());
}
return result;
}
console.log(test(array));
You can first sort() the array in ascending order and then loop through half of the array. And push() the values at corresponding indexes.
let arr = [2,4,7,1,3,8,9];
function order(arr){
let res = [];
arr = arr.slice().sort((a,b) => a-b);
for(let i = 0; i < Math.floor(arr.length/2); i++){
res.push(arr[i],arr[arr.length - 1 - i]);
}
return arr.length % 2 ? res.concat(arr[Math.floor((arr.length - 1)/2)]) : res;
}
console.log(order(arr))
You could sort the array, then copy and reverse and push to another array
const a = [2,4,7,1,3,8,9];
a.sort();
const b = a.slice().reverse();
const res = [];
for (let i = 0; i < a.length; i++) {
if (res.length < a.length) res.push(a[i]);
if (res.length < a.length) res.push(b[i]);
}
console.log(res);
Or use a Set
const a = [2,4,7,1,3,8,9];
a.sort();
const b = a.slice().reverse();
const res = new Set();
a.forEach((e, i) => (res.add(e), res.add(b[i])));
console.log(Array.from(res));
There are many ways are available to do this. And my solution is one of themm i hope.
Find max and min value, push them into another array. And delete max, min from actual array.
let array=[2,4,7,1,3,8,9];
let finalArray = [];
let max, min;
for(let i = 0; i < array.length; i++) {
max = Math.max(...array);
min = Math.min(...array);
finalArray.push(min);
finalArray.push(max);
array = array.filter(function(el) {
return el != max && el != min;
})
}
console.log(finalArray);
After sorting array this would work
myarr = [1,2,3,4,5,6];
let lastindex = myarr.length-1;
for(let i = 1 ; i <= myarr.length/ 2; i = i+2) {
ele = myarr[i];
myarr[i] = myarr[lastindex];
myarr[lastindex] = ele;
lastindex--;
}
Final Output will be: [1, 6, 3, 5, 4, 2]
You can use two iterators after sorting your array, one goes ascending and the other goes descending, until they cross each other.
Here's the code:
const array = [2, 4, 7, 1, 3, 8, 9];
const test = arr => {
const result = [];
const sortedArr = array.sort((a, b) => a - b);
for (let i = 0, j = sortedArr.length - 1; i <= j; i++, j--) {
result.push(sortedArr[i]);
i == j || result.push(sortedArr[j]);
}
return result;
};
console.log(test(array));
You can easily achieve the result using two pointer algorithm
function getValue(arr) {
const result = [];
let start = 0,
end = arr.length - 1;
while (start < end) result.push(arr[start++], arr[end--]);
if (start === end) result.push(arr[start]);
return result;
}
const array = [2, 4, 7, 1, 3, 8, 9];
const sorted = array.sort();
console.log(getValue(sorted));

Group array elements into set of n

I have an array
let arr = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14];
I want to group it into a set of n arrays such that first n elements in result[0] next n elements in result[1] and if any element is remaining it is discarded.
let sampleOutput = [[0, 1, 2, 3, 4, 5, 6], [7, 8, 9, 10, 11, 12, 13]] for n = 7;
Here is my code:
function group5(arr, len) {
let result = [];
let loop=parseInt(arr.length/len)
for (let i=0; i<arr.length; i+=len) {
let x = []; let limitReached = false;
for (let j=0; j<len; j++) {
if (arr[i+j]) {
x.push(arr[i+j]);
} else {
limitReached = true;
break;
}
}
if (!limitReached) {
result.push(x);
} else {
break;
}
}
return result;
}
But I am unable to get expected result. I have tried following things.
Map function
Running i loop to arr.len
Checking arr.len % 7
Creating an array for every third element.
This question is not duplicate of Split array into chunks because I have to discard extra elements that can not be grouped into sets of n.
I have to keep the original array Immutable because I am using this on props in a child component. I need a function that does not modify the original array.
It's pretty straigthforward using Array.from
const list = [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14];
function chunkMaxLength(arr, chunkSize, maxLength) {
return Array.from({length: maxLength}, () => arr.splice(0,chunkSize));
}
console.log(chunkMaxLength(list, 7, 2));
What about :
function group5(arr, len) {
let chunks = [];
let copy = arr.splice(); // Use a copy to not modifiy the original array
while(copy.length > len) {
chunks.push(copy.splice(0, len));
}
return chunks;
}
You could use a combination of reduce and filter to achieve the expected result. This example gives you a third control over length which makes the code a bit more reuseable.
let arr = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14];
const groupNumber = 7;
const groupCount = 2;
const groupArray = (group, size, length) => group.reduce((accumulator, current, index, original) =>
((index % size) == 0)
? accumulator.concat([original.slice(index, index + size)])
: accumulator, []
).filter((single, index) => index < length)
const test = groupArray(arr, groupNumber, groupCount);
console.log(test);
Step by Step
const groupArray = (group, size, length) => {
// if (index modulus size) equals 0 then concat a group of
// length 'size' as a new entry to the accumulator array and
// return it, else return the accumulator
const reducerFunc = (accumulator, current, index, original) =>
((index % size) == 0)
? accumulator.concat([original.slice(index, index + size)])
: accumulator
// if the current index is greater than the supplied length filter it out
const filterFunc = (single, index) => index < length;
// reduce and filter original group
const result = group.reduce(reducerFunc, []).filter(filterFunc)
return result;
}
Also (apart from the existing approaches) you can have a recursive approach like this
function chunks(a, size, r = [], i = 0) {
let e = i + size;
return e <= a.length ? chunks(a, size, [...r, a.slice(i, e)], e) : r;
}
function chunks(a, size, r = [], i = 0) {
let e = i + size;
return e <= a.length ? chunks(a, size, [...r, a.slice(i, e)], e) : r;
}
var arr = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14];
console.log('Chunk with 3: ', chunks(arr, 3));
console.log('Chunk with 4: ', chunks(arr, 4));
console.log('Chunk with 5: ', chunks(arr, 5));
console.log('Chunk with 6: ', chunks(arr, 6));
console.log('Chunk with 7: ', chunks(arr, 7));
I able to solve the problem with this code
function groupN(n, arr) {
const res = [];
let limit = 0;
while (limit+n <= arr.length) {
res.push(arr.slice(limit, n + limit));
limit += n
}
return res
}
I usually prefer declarative solutions (map, reduce, etc), but in this case I think a for is more understandable:
function groupArray(array, num) {
const group = [];
for (let i = 0; i < array.length; i += num) {
group.push(array.slice(i, i + num));
}
return group;
}

Categories