Maintain the duplicates in the sum of array integers - javascript

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

Related

How to Remove any consecutive sequence in Javascript?

I am trying to solve this.
Nominal Case:
For the array[1,2,3,5,2,4,7,54], and the number 6. The sequences[1,2,3] and [4,2] will be removed because the add up to 6. function will return [5,7,54]. If two sequences overlap, remove the first sequence.
Overlapping Case:
For the array [1,2,3,9,4,1,4,6,7] and the number 5, the sequence [2,3,] and [4,1] are removed because they add up to 5. For the [4,1] case. you see that [4,1,4] represents two overlapping sequences. because [4,1] adds up to 5 first is removed and the 4 is not removed even through [1,4] adds up to 5. We say that [4,1] and [1,4] overlap to give [4,1,4] and in those cases the first of the overlapping sequences is removed . functin will return [1,9,4,6,7]
function consecutive(arr, len, num) {
var newarr = [];
for (let i = 1; i < len; i++) {
var sum = arr[i] + arr[i + 1];
if (sum == num) {
newarr.push(arr[i]);
newarr.push(arr[i + 1]);
}
}
return newarr;
}
let arr = [1, 2, 3, 5, 2, 4, 7, 54];
let len = arr.length;
let num = 6;
console.log(consecutive(arr, len, num));
Get Wrong Output
[2,4]
You could store the target index of wrong items and if no one to filter out check the next elements if they sum up to the wanted value.
function consecutive(array, num) {
return array.filter(
(wrong => (v, i, a) => {
if (i <= wrong) return false;
let sum = 0, j = i;
while (j < a.length) {
if ((sum += a[j]) === num) {
wrong = j;
return false;
}
j++;
}
return true;
})
(-1)
);
}
console.log(consecutive([1, 2, 3, 5, 2, 4, 7, 54], 6));

How to merge an array with another one

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

JavaScript algorithm: is there a way to sort an already sorted array with the absolute values of its elements

I got this question during an interview.
I have an array that contains both negative and positive integers that are already sorted e.g.
const array = [-5, -3, 0, 2,7]
I am trying to write a function to sort the array using the absolute values of its elements. So the sorted array would be [ 0, 2, 3, 5, 7 ]
Here is my attempt
function sortArrayWithAbsoluteValue(array) {
const result = array.map(num => Math.abs(num)).sort((a,b) => a - b)
return result
}
Apparently, this works but it doesn't take advantage of the fact that the array is already sorted . Is there a better or more clever/efficient way to sort this?
the easiest solution is to introduce a new array and simply unshift it with elements from the first array
const array = [-9, -8, -5, -3, -2, 0, 2,7];
const newArray = [];
let i = 0, j = array.length - 1;
while(i <= j) {
const first = Math.abs(array[i]);
const last = Math.abs(array[j]);
if(first > last){
newArray.unshift(first)
i++;
}
else {
newArray.unshift(last)
j--;
}
}
console.log(newArray)
But this solution could be challenged by interviewers as unshift operator is slow o(n) so we can create newArray with the same size as array and then simply fill it in a similar way
const array = [-9, -8, -5, -3, -2, 0, 2,7];
const newArray = new Array(array.length);
let i = 0, j = array.length - 1, l = array.length - 1;
while(i <= j) {
const first = Math.abs(array[i]);
const last = Math.abs(array[j]);
if(first > last){
newArray[l] = first;
i++;
}
else {
newArray[l] = last;
j--;
}
l--;
}
console.log(newArray)
hope it helps!
You can let two indexes move towards eachother from either ends of the input array and based on how they compare, you copy the absolute value to the target array, filling it from end to front:
function absSorted(array) {
let result = Array(array.length);
for (let k = array.length - 1, i = 0, j = k; k >= 0; k--) {
result[k] = Math.abs(array[-array[i] < array[j] ? j-- : i++]);
}
return result;
}
const array = [-5, -3, 0, 2, 7];
console.log(absSorted(array));
You can use two iterators. One iterator starts from left and the other from right. Since the array is sorted one iterator points to the max absolute value. Store this value in a new array and iterate that iterator
const array = [-5, -3, 0, 2,7]
function f(array) {
let i = 0;
let j = array.length - 1;
const newArray = [];
while (i <= j) {
if (Math.abs(array[i]) < Math.abs(array[j])) {
newArray.push(Math.abs(array[j]));
--j;
} else {
newArray.push(Math.abs(array[i]));
++i;
}
}
return newArray;
}
console.log(f(array));
You can start at the min values with the inverted logic to get an increasing sort:
const array = [-5, -3, 0, 2, 7]
function g(array) {
let j = 0;
while (j < array.length && array[j] < 0) {
++j;
}
let i = j - 1;
const newArray = [];
while (i >= 0 && j < array.length) {
if (Math.abs(array[i]) < Math.abs(array[j])) {
newArray.push(Math.abs(array[i]));
--i;
} else {
newArray.push(Math.abs(array[j]));
++j;
}
}
if (i >= 0) {
newArray.push(...array.slice(0, i + 1).reverse().map(el => -el));
}
if (j < array.length) {
newArray.push(...array.slice(j));
}
return newArray;
}
console.log(g(array));
I converted all the numbers to the absolute value first using map
Then using a while loop, I used the indexOf and Math.min functions and the spread operator (...) to find the index of the minimum number of the array
Then I removed that from the array using splice
const array = [-5, -3, 0, 2,7];
function resort(array) {
const newArray = [];
array = array.map(i => Math.abs(i));
while (array.length) {
const minIndex = array.indexOf(Math.min(...array));
newArray.push(array.splice(minIndex, 1)[0]);
}
return newArray;
}
console.log(resort(array));

How to shuffle an array without moving FALSY elements?

Here is my attempt; a slightly-modified Fisher-Yates algorithm. I am not sure how to make sure it's random though.
const shuffleWithoutMovingFalsies = array => {
const newArray = [...array];
const getRandomValue = (i, N) => ~~(Math.random() * (N - i) + i);
newArray.forEach((elem, i, arr, j = getRandomValue(i, arr.length)) => arr[i] && arr[j] && ([arr[i], arr[j]] = [arr[j], arr[i]]));
return newArray;
}
const array = [1, 2, null, 3, null, null, 4, 5, 6, null];
const shuffledArray = shuffleWithoutMovingFalsies(array);
console.log(shuffledArray);
All I did was add arr[i] && arr[j] && as a check to make sure both elements about to be swapped are NOT falsy.
That stops it from being a fair shuffle. For example, with the array [1, null, 2], 1 should have a 50% chance of staying put and a 50% chance of swapping with 2, but instead, the split is ⅔–⅓.
As long as the auxiliary memory isn’t an issue, I’d recommend extracting the elements, shuffling them, and putting them back for simplicity:
const shuffle = arr => {
for (let i = 0; i < arr.length - 1; i++) {
const j = i + Math.floor(Math.random() * (arr.length - i));
[arr[i], arr[j]] = [arr[j], arr[i]];
}
};
const shuffleTruthy = arr => {
const truthy = arr.filter(Boolean);
shuffle(truthy);
let j = 0;
for (let i = 0; i < arr.length; i++) {
if (arr[i]) {
arr[i] = truthy[j++];
}
}
};

Mini-Max Sum HACKERHANK JS, why isn't working?

I don't know what's wrong, my function miniMaxSum isn't summing 1+3+4+5. At the end, the result array turns into this [ 14, 12, 11, 10 ], when it should looks like this [ 14, 13, 12, 11, 10 ]
function miniMaxSum(arr) {
let results = [];
let actualValue = 0;
let skipIndex = 0;
for (let i = 0; i < arr.length; i++) {
//skip actual index
if (i == skipIndex) continue;
actualValue += arr[i];
//restart the loop
if (i == arr.length - 1) {
skipIndex++;
results.push(actualValue);
actualValue = 0;
i = 0;
}
}
console.log(results);
console.log(Math.min(...results), Math.max(...results));
}
console.log(miniMaxSum([1, 2, 3, 4, 5]));
You're over-complicating your algorithm by trying to check whether you should add the current number to the overall sum or not. Instead, all you need to do is run a loop over your array, to sum up all your elements in your array. This will give you the total sum of all your elements. Then, again, iterate through your array. For each element in your array subtract it from the sum you just calculated and push it into a new array. This will give you the sum if you were to not use the number in the ith position. You can then find the min/max of this using JavaScript's Math.min and Math.max functions.
Here is an example using .reduce() and .map() to calculate the final result:
const miniMaxSum = arr => {
const sum = arr.reduce((s, n) => n+s, 0)
const results = arr.map(n => sum - n);
return [Math.min(...results), Math.max(...results)];
}
const [min, max] = miniMaxSum([1, 2, 3, 4, 5]);
console.log(min, max);
If you prefer standard for loops, here is an implementation of the above in a more imperative style:
const miniMaxSum = arr => {
let sum = 0;
for(let i = 0; i < arr.length; i++) { // sum all elements
sum += arr[i];
}
let results = [];
for(let i = 0; i < arr.length; i++) {
results[i] = sum - arr[i]; // sum minus the current number
}
return [Math.min(...results), Math.max(...results)];
}
const [min, max] = miniMaxSum([1, 2, 3, 4, 5]);
console.log(min, max);
Assuming you're talking about this question.
Whenever you want to restart the loop, you're setting i=0 but observe that you also have increment statement i++ in for loop so, effectively i starts from 1, not 0. You need to set i=-1 so that i=-1+1 = 0 in subsequent iteration. After doing this, you need to handle a corner case. When skipIndex==arr.length-1, check if i == arr.length-1. If yes, do results.push(actualValue); for the last value and then for loop terminates because i < arr.length is false in next iteration.
Code:
function miniMaxSum(arr) {
let results = [];
let actualValue = 0;
let skipIndex = 0;
for (let i = 0; i < arr.length; i++) {
//skip actual index
if (i == skipIndex){
if(i == arr.length - 1)
results.push(actualValue);
continue;
}
actualValue += arr[i];
//restart the loop
if (i == arr.length - 1) {
skipIndex++;
results.push(actualValue);
actualValue = 0;
i = -1;
}
}
console.log(results);
console.log(Math.min(...results), Math.max(...results));
}
miniMaxSum([1, 2, 3, 4, 5]);
Output
[ 14, 13, 12, 11, 10 ]
10 14

Categories