0

So I have the following array :

let array = ['9h00','9h30','9h45','10h00','10h15']

Let's say I want to insert '9h15' between '9h00' && '9h30'

How would one do it in a fast & efficient solution ?

EDIT: I have been unclear, the index of the insert would change depending on the array. It won't always be the following position : array[1].

Thanks in advance!

0x01
  • 885
  • 7
  • 17
  • 1
    what is your not so fast and inefficient solution? – Nina Scholz Apr 27 '17 at 19:53
  • 3
    provided the array is sorted prior to insertion, you can [do a binary search](http://stackoverflow.com/questions/22697936/binary-search-in-javascript) for the correct position, then [insert into the array using `Array.splice`](http://stackoverflow.com/a/586189/1038832). – Churro Apr 27 '17 at 19:56
  • I would (not yet implemented) check the first digits before 'h' then along some conditionals check the first digit after the 'h' and insert if its a lower value. – 0x01 Apr 27 '17 at 19:56
  • @MEGADEVOPS You might not need to make two comparisons. Why not just remove the `h` and convert to a number before comparing? – Joseph Marikle Apr 27 '17 at 20:11

2 Answers2

1

If every item has the same format (\d?\d)h(\d{2}) then we can do the following :

First we need a function to convert the string to an object or something we can work with, I'll go with an object :

function timeStringToObj(str){
  var re = "^(\d?\d)h(\d\d)$";
  var h = str.replace(re, "$1");
  var m = str.replace(re, "$2");
  return {
    hours: parseInt(h),
    minutes: parseInt(m)
  };
}

Then we will need to ensure that the array is sorted, for instance "9h15" < "9h16" therefore "9h15"'s index is < "9h16"'s index , (if not use array.sort(/*some sorting function if necessary*/)) and loop through it to find the spot (I'll use a function of course), I'll consider your array as a global variable :

/**
*@param timeObjA an object that is the return value of a call of timeStringToObj
*@param timeObjB an object that is the return value of a call of timeStringToObj
*/
function AgeB(timeObjA, timeObjB){//A greater than or equal to B
  return (timeObjA.hours >= timeObjB.hours && timeObjA.minutes >= timeObjB.minutes);
}


/**
*@param a an object that is the return value of a call of timeStringToObj
*@param b an object that is the return value of a call of timeStringToObj
*/
function AleB(a, b){//A less than or equal to B
  return (timeObjA.hours <= timeObjB.hours && timeObjA.minutes <= timeObjB.minutes);
}


function putInTimeArray(str){
  var val = timeStringToObj(str);
  for(let i = 0 ; i < array.length ; i+=1){
    var curr = timeStringToObj(array[i]);


    //first check : elem >= last
    if( AgeB(val, curr) && i===(array.length-1) ){
      array.push(str);
      return true;
    }

    //second check : elem <= first
    if( AleB(val, curr) && i===0 ){
     array.unshift(str);
     return true;
    }

    //last check : first < elem < last
    if(i!=0 && i!=(array.length - 1)){
      if(AgeB(val, curr)){
        array.splice(i+1,0,str);
        return true;
      }
      if(AleB(val, curr){
        array.splice(i-1,0,str);//here i-1 is safe since i!=0 (condition)
        return true;
      }
    }//end of last check
  }//end of for-loop
}//end of function

If you're having doubts regarding my usage of splice please refer to this : How to insert an item into an array at a specific index?

EDIT

You'll probably need a more sophisticated regex to be more appropriate be this will do the job just fine if you don't go that crazy with those strings

Community
  • 1
  • 1
Vivick
  • 3,434
  • 2
  • 12
  • 25
-1

You can push and sort like:

array.push("9h15").sort().reverse(); // ["9h45", "9h30", "9h15", "9h00", "10h15", "10h00"]
cbertelegni
  • 423
  • 2
  • 11