Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I grab the two largest integers from a Javascript Array and return the value to the DOM?

I've written a solution to take a list of integers entered through a form. It works. It gives you the sum of the two largest integers and posts it in the DOM. However, it's not very efficient for large arrays of say 1 million integers.

How can I improve this solution to be more efficient.

App.js

 // This function reverses the order of the array and places the biggest numbers first
 function sortNumber(a, b) {
   return b - a;
 }


 // this function is used to ensure the user didn't enter any letters
 function getArray() {
   var alphaExp = /^[a-zA-Z]+$/;

   // This function takes the array, orders it, adds the sum of the two largest numbers and returns the value
   
   function sumOf(x) {
     
       // Sort the ary with the sortNumber function
       array.sort(sortNumber);
   
     // Then we add the two biggest numbers of the array and save it to the result variable.
     
       var result = array[0] + array[1];
     
       // Then we share the result with the user by updating the browser
       var myHeading = document.querySelector('h2');
       myHeading.textContent = "The sum of your two biggest numbers is: " + result;
       
     // Like a good student, it's important to show your work
       var showYourWork = document.querySelector('h3');
       showYourWork.textContent = array[0] + " + " + array[1] + " = " + result;
     }
     // This grabs the value of the input
   var arrayField = document.getElementById('arrayField').value;

   if (arrayField.match(alphaExp)) {
     
     // Fail if user enters letters
     var raiseError = document.querySelector('h5');
     raiseError.textContent = 'No not letters! We want numbers!!';
   } else {
     var array = JSON.parse("[" + arrayField + "]");
     if (arrayField.length < 2) {
       
       // If the user enters only 1 number, tell them to enter more!
       var raiseError = document.querySelector('h5');
       raiseError.textContent = 'Please enter atleast two numbers seperated by commas for us to add!'
     } else {
       
       // When the user enters a list of numbers, run the sumOf function.
       sumOf(arrayField);
       
       //Make the error go away
       var raiseError = document.querySelector('h5');
       raiseError.textContent = '';
     }
   }
 };

 // use an eventlistener for the event (This is where the magic happens)
 var subButton = document.getElementById('subButton');
 subButton.addEventListener('click', getArray, false);
like image 662
Ryan James Avatar asked Feb 07 '16 04:02

Ryan James


2 Answers

You don't have to sort it, just search linearly for the two biggest ones:

EDIT: the code below should work now and is asymptotically faster than the OP's code. The OP does sorting first which can be done in O(n log n), assuming a random list. My code does a linear search through the list in O(cn) with c = 2 (the two loops are not necessary but simple). The solution for ceil(n log n) = 2n with n a positive integer is 14, that is for every list longer than 14 entries the code below is faster. E.g.: for one million entries the relation is 13,815,511 to 2,000,000, more than six times faster. You can do the same thing in a single loop which halves the runtime (theoretically, but it is also a tiny bit faster because of the better locality).

function maxtwo_wrong(a){
    var b1 = -Infinity;
    var b2 = -Infinity;

    for (var i=0; i < a.length; i++) {
        if (a[i] > b1) {
            b1 = a[i];
        }
    }
    for (var i=0; i < a.length; i++) {
        if (a[i] > b2 && a[i] < b1) {
            b2 = a[i];
        }
    } 
    return [b1,b2];
}

EDIT-2: The code above maxtwo_wrong seems not to fit the requirements, so I wrote another one maxtwo_rightand put it below. Please, OP, tell me which one fulfills your requirements such that I can delete the wrong one.

EDIT-3: made it simpler and correct.

function maxtwo_right(a){
    var b1 = -Infinity;
    var b2 = -Infinity;

    for (var i=0; i < a.length; i++) {
        // If the current entry is bigger than variable b1
        // keep the old value in the variable b2 and set b1 to the
        // value of the current entry
        if (a[i] > b1) {
            b2 = b1;
            b1 = a[i];
        }
        // if the current entry equals b1 set the variable b2 to
        // the value of the current entry
        else if(a[i] === b1){
            b2 = a[i];
        }
    }
    // return the sum of the two variables as requested
    return b1 + b2;
}
like image 136
deamentiaemundi Avatar answered Sep 28 '22 16:09

deamentiaemundi


I finally found some time to sit down and work this one out. I was looking at the problem all wrong.

Here is my new solution

// This function adds the sum of the two largest integers of an array and returns the value
function topTwoInt(theArray) {
    var intArray = theArray;
    var highestInt = -Infinity;
    var secondHighestInt = -Infinity;
    var answer = 0;
    //Loop through the array
    for (var i=0; i < intArray.length; i++) {
        //grab the biggest int and assign it to the highestInt variable;
        if (intArray[i] > highestInt) {
            secondHighestInt = highestInt;
            highestInt = intArray[i]; 
        }
        //If the next number is equal too highestInt or greater than secondHighestInt
        //Make that number become the new secondHighestInt
        else if(intArray[i] === highestInt || intArray[i] > secondHighestInt) {
            secondHighestInt = intArray[i];
        }
    }
    answer = highestInt + secondHighestInt;
    return answer;
};

This solution is largely inspired by @deamentiaemundi Thanks man.

like image 33
Ryan James Avatar answered Sep 28 '22 17:09

Ryan James