JavaScript - more efficient way to truncate an array - javascript

I have an int array sorted ascending and I would like to remove array items from the tail according to the specific boundary. What is a better way to truncate an array in my case? Consider next code snippets:
var a = [1, 2, 3, 4];
var length = a.length;
var boundary = 2;
var count = 0;
for (var i = length - 1; i >= 0; i--) {
if (a[i] > boundary) {
a[i] = null; // or delete a[i] ???
count++;
}
}
a.length -= count;
Or the same but using splice:
for (var i = length - 1; i >= 0; i--) {
if (a[i] > boundary) {
a.splice(i, 1);
}
}

a.length -= count;
Thats sufficient ;) (as length is not a simple property, but rather a getter/setter which truncates/adds elements (ref))
Alternatively use splice:
a.splice(-count, count);

In modern engines, or with a shim, you can use Array.prototype.findIndex:
var a = [1, 2, 3, 4];
var boundary = 2;
a.length = a.findIndex( x => x > boundary );
console.log( a );
Since you're array is sorted you can also just use Array.prototype.filter:
var a = [1, 2, 3, 4];
var boundary = 2;
a = a.filter( x => x <= boundary );
console.log( a );
which may be slightly (negligibly) slower if the array is huge, but has more support in older engines.

Don't delete array entries at the end of an array to truncate it. Deleting array entries removes them from the array by creating a sparse array: the length property of the array remains unchanged:
var a = [1,2,3,4];
console.log( "a.length %s", a.length);
delete a[3];
console.log( "a[3] after deletion: %s", a[3]);
console.log( "a.length after deletion %s", a.length);
console.log( "a[3] still exists: %s", a.hasOwnProperty("3"));
Similar considerations apply to setting array entries to null. They will no longer test as truthy in a conditional expression, but have not been removed. As before the length of the array will remain unchanged.
Setting the length of the an array to something shorter than its existing value will truncate it in place. There are many ways of finding the boundary position at which to truncate the array. I suggest choosing one that appears natural to you and works in target browsers. E.G. using forSome on a sorted array may not meet your requirements :)
var a = [1,2,3,4];
var boundary = 2;
a.some(
(c,i) => {
if( c > boundary)
{ a.length = i;
return true;
}
}
);
console.log( a)
If using splice, note that all entries from the boundary position to the end of array can be deleted in one call rather than deleting them one at a time:
var a = [1,2,3,4];
var boundary = 2;
for( var i = a.length-1; a[i]>boundary; --i) {} // linear search
a.splice(i+1);
console.log(a);

Related

HackerRank - Minimum Swaps 2 Timeout

This challenge asks that you find the minimum number of swaps to sort an array of jumbled consecutive digits to ascending order. So far my code passes most of the tests, however there are four that fail due to timeout. Could anyone explain why my code is timing out? Is there a way to make it find an answer faster?
function minimumSwaps(arr) {
const min = Math.min(...arr);
let swapCount = 0;
const swap = (array, a, b) => {
let test = array[a];
array[a] = array[b];
array[b] = test;
}
for(let i=0; i<arr.length; i++){
if(arr[i]!==i+min){
swap(arr, i, arr.indexOf(i+min));
swapCount++;
}
}
return swapCount;
}
I thought it was a good solution since it only has to iterate over the length of the array once? I'd love to be able to understand why this isn't performing well enough
Your big issue is with the call to arr.indexOf, as that has to scan the entire array each time you do a swap. You can work around that by generating a reverse lookup from value to array index before starting to sort, and then maintaining that list during the sort. Note that you don't need to do a full swap, only copy the value from arr[i] to its correct place in the array since you don't revisit a number once you have passed it. Also you don't need min, as under the conditions of the question it is guaranteed to be 1, and you don't need to look at the last value in the array since by the time you get to it it has to be correct.
function minimumSwaps(arr) {
const indexes = arr.reduce((c, v, i) => (c[v] = i, c), []);
const len = arr.length - 1;
let swapCount = 0;
for (let i = 0; i < len; i++) {
if (arr[i] !== i + 1) {
arr[indexes[i+1]] = arr[i];
indexes[arr[i]] = indexes[i+1];
swapCount++;
}
}
return swapCount;
}
console.log(minimumSwaps([7, 1, 3, 2, 4, 5, 6]));
console.log(minimumSwaps([4, 3, 1, 2]));
console.log(minimumSwaps([2, 3, 4, 1, 5]));
console.log(minimumSwaps([1, 3, 5, 2, 4, 6, 7]));
I think we should flip function not search function.
function minimumSwaps($arr) {
$outp = 0;
$result = array_flip($arr);
for($i=0; $i<count($arr); $i++){
if($arr[$i] != $i +1){
$keyswp = $result[$i + 1];
$temp = $arr[$i];
$arr[$i] = $i + 1;
$arr[$keyswp] = $temp;
$tempr = $result[$i + 1];
$result[$i + 1] = $i +1;
$result[$temp] = $keyswp;
$outp = $outp + 1;
}
}
return $outp;
}
Here is my solution , it is similar to Nick's except instead of the Array.Proptytype.indexOf method I used an object literal to map the indices of each value for a better Time complexity since search in object literal is O(1) (You can use ES6 maps too). Here is the code
function minimumSwaps(arr) {
let count = 0;
let search = arr.reduce((o, e, i) => {
o[e] = i
return o
}, {})
for(let i =0 ; i < arr.length - 1; i++){
let j = search[i+1]
if(arr[i] !== i+1) {
[arr[i], arr[j]] = [arr[j], arr[i]]
search[arr[i]] = i;
search[arr[j]] = j;
count += 1
}
}
console.log(arr)
return count
}
As suggested by others, you shouldn't use the indexOf method as it makes your solution O(n^2) (As the indexOf method has to scan the entire array again). You can create a position map array before hand and use it later during the swap. It will keep your solution linear. Here is the detailed explanation and solution to the HackerRank Minimum Swaps 2 Problem in java, c, c++ and js, using this method.

leetcode 3sum assistance, how can i optimize this answer?

I have a solution that seems to pass most of the tests but is too slow. If i'm not mistaken, the complexity is O(n^3) due to the three for loops.
My idea was to start at the first three positions of the array at i, j and k, sum them, and see if it adds up to 0.
The functions objective is:
Given an array nums of n integers, are there elements a, b, c in nums such that a + b + c = 0? Find all unique triplets in the array which gives the sum of zero.
Note:
The solution set must not contain duplicate triplets.
Example:
Given array nums = [-1, 0, 1, 2, -1, -4],
A solution set is:
[
[-1, 0, 1],
[-1, -1, 2]
]
var threeSum = function(nums) {
var originalArray = nums
var lengthArray = nums.length
//sort array smallest to largest
nums.sort(function(a,b) {
return a-b
})
function arrayEqual(array1, array2){
var equal = false
array1.forEach((value1) => {
if(array1 === array2){
equal = true
}
})
return equal
}
var sum = 0;
var answerArray = [];
//start from first digit and add from there
for(var i = 0; i<lengthArray; i++){
for(var j = i+1; j<lengthArray; j++){
for(var k = j+1; k<lengthArray; k++){
if((nums[i]+nums[j]+nums[k] === 0)){
if(!arrayEqual(answerArray, [nums[i],nums[j],nums[k]])){
answerArray.push([nums[i],nums[j],nums[k]])
}
}
}
}
}
return Array.from(new Set(answerArray.map(JSON.stringify)), JSON.parse)
};
How can i get around having to use three for loops to make this work (aka how do i optimize this solution?)
Think this problem in this way. Choose any number from the array say k. Now you need to find two other numbers in the array which add to -k. The resulting sum of three numbers will be k + (-k) = 0.
So this problem is reduced to find two numbers in the array which adds to a given number which is O(n) using two pointers method if given array is sorted.
In a nutshell, sort the array, take each number (k) one by one (O(n)), find two other numbers with sum -k (O(n)).
Total time complexity : O(n) * O(n) = O(n2)
You can solve the problem in a runtime of O(n^2). Here is the solution using JavaScript
var threeSum = function(nums) {
var solutions = [];
var target = 0;
nums.sort(function(a, b) {
return a - b;
});
for(var i = 0; i < nums.length - 2; i++) {
if(i === 0 || (i > 0 && nums[i] !== nums[i - 1])) {
var lo = i + 1;
var hi = nums.length - 1;
var sum = - nums[i];
while(lo < hi) {
if(nums[lo] + nums[hi] === sum) {
solutions.push([nums[i],nums[lo],nums[hi]]);
while (lo < hi && nums[lo] === nums[lo + 1]) lo++;
while (lo < hi && nums[hi] == nums[hi-1]) hi--;
lo++; hi--;
}else if (nums[lo] + nums[hi] > sum) {
hi--;
}else {
lo++;
}
}
}
};
return solutions;
}

Reversing certain number of elements in an array javascript

I am working on a code where I need to reverse certain no of elements in an array and rest should remain same. For example is an array has values of 1,2,3,4,5,6 and I have to reverse 4 elements of it then output should be 4,3,2,1,5,6. I am using below code to achieve this but getting error, please suggest.
function reverseArray(n, a) {
var interimArray1 = [];
//var interimArray2=[];
//var finalArray=[];
for (var i < n; i >= 0; i--) {
interimArray1.push[a[i]];
}
for (var i = n; i < a.length; i++) {
interimArray1.push[a[i]];
}
for (var i = 0; i < interimArray1.length; i++) {
console.log(interimArray1[i]);
}
}
var arr = [1, 2, 3, 4, 5, 6];
var num = 4;
reverseArray(num, arr);
The error in your code is that you intend to call the push method on a[i] like so:
interimArray1.push(a[i]);
but instead you write:
interimArray1.push[a[i]];
You make that mistake twice. To give arguments to the push method, you must use round parenthesis ().
With that fixed, you will see that your code works perfectly.
You can use Array#slice, Array#splice as follow.
function partialReverse(arr, num, from = 0) {
var slicedArr = arr.slice(from, num + from);
arr.splice(from, num); // Remove `num` items from array
arr.splice(from, 0, ...slicedArr.reverse()); // Add `num` reversed items
return arr;
}
var arr = [1, 2, 3, 4, 5, 6];
console.log(partialReverse(arr, 4, 0)); // Reverse four items from `arr` starting from 0th index
console.log(partialReverse(arr, 4, 1)); // Reverse four items from `arr` starting from 1st index
Lots of hints but you seem to be missing them. ;-)
You need to assign an initial value to i, so:
for (var i = n; ... )
===========^
Also, you need to use () to call functions, not [], so:
interimArray1.push(a[i]);
==================^====^
Same in the following for block. Otherwise, the code works though it's more verbose than it needs to be.
This is working :
I'm sure there are faster ways of doing it. Also, it will only work for elements at the beginning of the array but you can adjust the function for what you want to achieve.
var reverseArray = function(arr,elementsToReverse) {
var tempArrayRev = [];
var tempArray = [];
for (var i=0;i<arr.length;i++) {
if (i < elementsToReverse) {
tempArrayRev[i] = arr[i];
} else {
tempArray.push(arr[i]);
}
}
return tempArrayRev.reverse().concat(tempArray);
}
var array = [1,2,3,4,5,6];
document.getElementById('arrayOutput').innerHTML += reverseArray(array,4);
<div id="arrayOutput">Array :<br></div>
This is the answer you can test it.
function reverseArray(n, a) {
var interimArray1 = [];
for (var i = 0; i < a.length; i++) {
interimArray1.push(a[i]);
}
for (var i = num; i >=0; i--) {
interimArray1[i-1] = a[n - i];
}
for (var i = 0; i < interimArray1.length; i++) {
console.log(interimArray1[i]);
}
}
var arr = [1, 2, 3, 4, 5, 6];
var num = 4;
reverseArray(num, arr);
You could use something like this.
function reverseArray(n, arrIn) {
// Splice splits the array in 2 starting at 0 index going n long
var arrOut = arrIn.splice(0,n);
// reverse is pretty straight forward
arrOut = arrOut.reverse();
// Concat joins the two together
return arrOut.concat(arrIn);
}

Delete Record From Javascript Array Object

i have a java script array object and i want to delete items from a specific index in that object, i have a comma separated string of that indexes. problem is that when i delete it using splice array indexes got changed, and other indexes's object not got deleted.
var DeletedConditions="3, 5, 19, 50";
for (var k = 0; k < DeletedConditions.split(", ").length; k++) {
ConditionObject.splice(DeletedConditions.split(", ")[k], 1);
}
DeletedConditions string can be anything.
please help me out. how to get this done.
First of all, I suggest you officially turn the indexes into a formal array. Having a string as an index reference, you are prone to missing a split shall there be a case where the values are not separated by ,
Then the code:
var content = ['foo', 'bar', 'baz', 'bam', 'dom', 'zok'],
deleteIndexes = [5, 1, 3],//should delete zok, bar, bam
i;
//sort from least to greatest: [1, 3, 5]
deleteIndexes.sort(function(a, b) {
return a - b;
});
//we loop backwards (performance enhancement)
//now we loop from greatest to least
//we now splice from greatest to least
//to avoid altering the indexes of the content as we splice
for (i = deleteIndexes.length; i-- > 0;) {
content.splice(deleteIndexes[i],1);
}
console.log(content); //["foo", "baz", "dom"]
​
You can always decrement the k iterator after splicing inside the loop:
k--;
var DeletedConditions="3, 5, 19, 50";
var list = DeletedConditions.split(", ")
for (var k = 0; k < list.length; k++) {
// using splice here
list.splice(k,1);
k--;
}
console.log(list.join(', '))
Removing an item from the beginning of the array shuffles the later elements up and changes their indices, as you've observed. But if you go through the list of items to remove backwards then it will remove the later elements first so the indices will still be correct for the elements closer to the beginning of the array.
Also, please don't do the .split() operation on every loop iteration - the inefficiency might not make much difference on a string with four numbers in it, but it makes the code kind of messy and on principle it is just kind of yucky.
var DeletedConditions="3, 5, 19, 50",
delCondArr = DeletedConditions.split();
for (var k = delCondArr.length - 1; k >= 0; k--) {
ConditionObject.splice(delCondArr[k], 1);
}
If there's a possibility that the DeletedConditions strig might not be ordered just add a .sort() after you split it:
delCondArr = DeletedConditions.split().sort(function(a,b){return a-b;});
...in which case you don't need to loop backwards.
It might be easiest to copy the original array, omitting the deleted items in the process. Something like this would do the trick...
var DeletedConditions="3, 5, 19, 50";
DeletedConditions = DeletedConditions.split(', ');
var newConditionObject = [];
for(var k = 0; k < ConditionObject.length; ++k) {
if(DeletedConditions.indexOf(k) !== -1) { continue; }
newConditionObject.push(ConditionObject[k]);
}
// result is in `newConditionObject`
console.log(newConditionObject);
var fruits = new Array("apple", "banana", "grapes", "oranges","mosambi","aaa","bbb","ccc");
var DeletedConditions="1,3,4,5";
var indexArray = new Array;
indexArray = DeletedConditions.split(",");
for (var i = 0; i < indexArray.length; i++) {
fruits.splice(indexArray[i], 1);
}

Alternate method to splice function in JavaScript

Hi i am working on LIME programming which is a subset of javascript.
i need to use javascript.splice to remove certain elements from my array, sad to say, LIME does not support splice function.
Any idea how do i create my own function to remove elements from an array?
Thanks for your time.
EDIT: Manage to create a simple function.
function removeElements(array, index)
{
var tempArray = new Array();
var counter = 0;
for(var i = 0; i < array.length; i++)
{
if(i != index)
{
tempArray[counter] = array[i];
counter++;
}
}
return tempArray;
}
Array.prototype.splice is fully defined in ECMA-262 §15.4.4.12, so use that as your spec and write one. e.g.
15.4.4.12 Array.prototype.splice (start, deleteCount [ , item1 [ ,item2 [ , … ] ] ] )
When the splice
method is called with two or more
arguments start, deleteCount and
(optionally) item1, item2, etc., the
deleteCount elements of the array
starting at array index start are
replaced by the arguments item1,
item2, etc. An Array object containing
the deleted elements (if any) is
returned. The following steps are
taken:...
You will probably have to create a new array, copy the members up to start from the old array, insert the new members, then copy from start + deleteCount to the end to the new array.
Edit
Here is an amended splice, the first I posted was incorrect. This one splices the array passed in and returns the removed members. It looks a bit long but I tried to keep it close to the spec and not assume support for any complex Array methods or even Math.max/min. It can be simplified quite a bit if they are.
If push isn't supported, it can be replaced fairly simply too.
function arraySplice(array, start, deleteCount) {
var result = [];
var removed = [];
var argsLen = arguments.length;
var arrLen = array.length;
var i, k;
// Follow spec more or less
start = parseInt(start, 10);
deleteCount = parseInt(deleteCount, 10);
// Deal with negative start per spec
// Don't assume support for Math.min/max
if (start < 0) {
start = arrLen + start;
start = (start > 0)? start : 0;
} else {
start = (start < arrLen)? start : arrLen;
}
// Deal with deleteCount per spec
if (deleteCount < 0) deleteCount = 0;
if (deleteCount > (arrLen - start)) {
deleteCount = arrLen - start;
}
// Copy members up to start
for (i = 0; i < start; i++) {
result[i] = array[i];
}
// Add new elements supplied as args
for (i = 3; i < argsLen; i++) {
result.push(arguments[i]);
}
// Copy removed items to removed array
for (i = start; i < start + deleteCount; i++) {
removed.push(array[i]);
}
// Add those after start + deleteCount
for (i = start + (deleteCount || 0); i < arrLen; i++) {
result.push(array[i]);
}
// Update original array
array.length = 0;
i = result.length;
while (i--) {
array[i] = result[i];
}
// Return array of removed elements
return removed;
}
If you don't care about order of the array and you're just looking for a function to perform splice, here's an example.
/**
* Time Complexity: O(count) aka: O(1)
*/
function mySplice(array, start, count) {
if (typeof count == 'undefined') count = 1
while (count--) {
var index2remove = start + count
array[index2remove] = array.pop()
}
return array
}
If you want to return the removed elements like the normal splice method does this will work:
/**
* Time Complexity: O(count) aka: O(1)
*/
function mySplice(array, index, count) {
if (typeof count == 'undefined') count = 1
var removed = []
while (count--) {
var index2remove = index + count
removed.push(array[index2remove])
array[index2remove] = array.pop()
}
// for (var i = index; i < index + count; i++) {
// removed.push(array[i])
// array[i] = array.pop()
// }
return removed
}
This modifies the original Array, and returns the items that were removed, just like the original.
Array.prototype.newSplice = function( start, toRemove, insert ) {
var remove = this.slice( start, start + toRemove );
var temp = this.slice(0,start).concat( insert, this.slice( start + toRemove ) );
this.length = 0;
this.push.apply( this, temp );
return remove;
};
Comparison test: http://jsfiddle.net/wxGDd/
var arr = [0,1,2,3,4,5,6,7,8];
var arr2 = [0,1,2,3,4,5,6,7,8];
console.log( arr.splice( 3, 2, 6 ) ); // [3, 4]
console.log( arr ); // [0, 1, 2, 6, 5, 6, 7, 8]
console.log( arr2.newSplice( 3, 2, 6 ) ); // [3, 4]
console.log( arr2 ); // [0, 1, 2, 6, 5, 6, 7, 8]
It could use a little extra detail work, but for the most part it takes care of it.
Here is a simple implement in case the Array.prototype.splice dispears
if (typeof Array.prototype.splice === 'undefined') {
Array.prototype.splice = function (index, howmany, elemes) {
howmany = typeof howmany === 'undefined' || this.length;
var elems = Array.prototype.slice.call(arguments, 2), newArr = this.slice(0, index), last = this.slice(index + howmany);
newArr = newArr.concat.apply(newArr, elems);
newArr = newArr.concat.apply(newArr, last);
return newArr;
}
}
Are there any other methods that are missing in LIME's Array implementation?
Assuming at least the most basic push() and indexOf() is available, there's several ways you could do it. How this is done would depend on whether this is destructive method or whether it should return a new array. Assuming the same input as the standard splice(index, howMany, element1, elementN) method:
Create a new array named new
push() indexes 0 to index onto the new array
Now stop at index and push() any new elements passed in. If LIME supports the standard arguments variable then you can loop through arguments with index > 2. Otherwise you'll need to pass in an array instead of a variable number of parameters.
After inserting the new objects, continue looping through the input array's elements, starting at index + howMany and going until input.length
I believe that should get you the results you're looking for.
I have used this below function as an alternative for splice()
array = mySplice(array,index,count);
above is the function call,
And this is my function mySplice()
function mySplice(array, index, count)
{
var newArray = [];
if( count > 0 )
{ count--;}
else
{ count++;}
for(i = 0; i <array.length; i++)
{
if(!((i <= index + count && i >= index) || (i <= index && i >= index + count)))
{
newArray.push(array[i])
}
}
return newArray;
}
I have done it very similar way using only one for loop
function removeElements(a,index,n){
// a=> Array , index=> index value from array to delete
// n=> number of elements you want to delete
let temp = []; // for storing deleted elements
let main_array = []; // for remaining elements which are not deleted
let k = 0;
for(let i=0;i<a.length;i++){
if((i===index) || ((index<i && i<n+index))){
temp[i]=a[i+1];
delete a[i];
}
if(a[i]!==undefined){
main_array[k] = a[i];
a[i] = main_array[k];
k++;
}
}
a=main_array;
return a;
}
a=[1,2,3,4,5];
console.log(removeElements(a,0,1));
follow link Jsfiddle
var a = [3, 2, 5, 6, 7];
var fromindex = 1
var toindex = 2;
for (var i = 0; i < a.length; i++) {
if (i >= fromindex + toindex || i < fromindex) {
console.log(a[i])
}
}
var a = [3, 2, 5, 6, 7];
var temp=[];
function splice(fromindex,toindex)
{
for (var i = 0; i < a.length; i++) {
if(i>=fromindex+toindex || i<fromindex)
{
temp.push(a[i])
}
}
return temp
}
console.log(splice(3,2))

Categories