Array Splice - Javascript - javascript

Its a very small issue and for the life of me I can't figure out what it is. My brain has locked itself from thinking. I need someone else to have a look this code.
The output of the code should be: [1,0,0,0]
UPDATE:
The function should be able to read an array of numbers and if it finds any zeros within the array it should move them to the end of the array.
The output of the code keeps coming as: [0,1,0,0]
var arrNum = [0,0,0,1];
function test() {
for(var i=0; i<arrNum.length; i++){
if(arrNum[i] == 0){
arrNum.splice(i,1)
arrNum.splice(arrNum.length, 1, 0)
}
}
return alert(arrNum)
}
Here is a working plunker.
Apologies for this, I know the issue is something very small but my brain has stopped working now and I need a fresh pair of eyes.

With the way you have it written, you need to loop in the reverse order. You end up skipping indexes when you remove the index. Looping in the reverse direction keeps you from skipping them.
for(var i=arrNum.length-1; i>=0; i--){

You can use unshift() to insert at beginning of an array and push() to the end...
var arrNum = [0,0,0,1];
var output = [];
function test()
{
for(var i=0; i<arrNum.length; i++)
{
if(arrNum[i] == 0)
output.push(0);
else
output.unshift(arrNum[i]);
}
return alert(output)
}

var arrNum = [0,0,0,1];
var result = [];
arrNum.forEach(function(v) {
!!v ? result.unshift(v) : result.push(v);
});
console.log(result);

You are iterating with index i = 0,1,2,3 and at the same time removing first elements of array. So your iteration can not see the 1, it jumps over as it is moved to already iterated index. Easiest would be to just reverse the loop to bypass the issue.
var arrNum = [0,0,0,1];
function test() {
for(var i= arrNum.length; i >= 0; i--){
if(arrNum[i] == 0){
arrNum.splice(i,1)
arrNum.splice(arrNum.length, 1, 0)
}
}
return alert(arrNum)
}

Prefer built-in functions every time possible.
var output = [];
[0,0,0,1].forEach(function(num) {
if(num == 0) output.push(0);
else output.unshift(num)
})

Why don't you use a temporary array to help? The problem with your code is that the splice() function modifies the original array, and you are doing it inside the loop.
The code below produces what you need:
var arrNum = [0,0,0,1];
var arrResult = new Array();
function test() {
for(var i=arrNum.length-1; i>=0; i--)
{
arrResult.push(arrNum[i]);
}
arrNum = arrResult;
return alert(arrNum);
}
With another array to store the new values, you gain flexibility to do whatever you need with the data of the first array.

A nice little way using Objects - busy learning them so just posting a variation of deligation
var methods = {
moveZero: function(arr){
//console.log(arr);
var newArr = [];
for(var i = 0; i < arr.length; i++){
if(arr[i] === 0){
newArr.push(arr[i]);
}else{
newArr.unshift(arr[i]);
}
}
console.log(newArr);
}
}
var arrNum = Object.create(methods);
arrNum.moveZero([0,0,50,56,85,0,0,43,10,0,1]);
JSFiddle - https://jsfiddle.net/ToreanJoel/qh0xztgc/1/

The problem was you are modifying an array while looping over it in if statement.
Here is a working plunker of your example.
var len = arrNum.length;
var index = 0;
while(len) {
if(arrNum[index] == 0) {
arrNum.splice(index,1);
arrNum.push(0);
} else {
++index;
}
--len;
}

As the operation you want to do is actually sorting, for readability and compactness of code maybe you should be doing this instead:
var arrNum = [0,1,0,0];
arrNum.sort(function(a, b) {
return a == 0 ? 1 : 0;
});
It can contain any number and will keep order of others than 0

Related

jQuery or JavaScript compare two arrays one contains an object

MyIds has just two Id numbers 1 and 2
var MyIds = [1,2]
but MyObject has three Id numbers 1, 2 and 3 (In reality this has about 500 Id's)
var MyObject = [{id:1,size:21,length:31},{id:2,size:22,length:32},{id:3,size:23,length:33}]
and I want to make a new variable that looks like this, I need some magic code that will compare the two variables and only return the details of the objects where the Is's match
var Result = [{id:1,size:21,length:31},{id:2,size:22,length:32}]
I'm happy to use jQuery if it help
Use Array.prototype.filter()
var Result = MyObject.filter(function(item){
return MyIds.indexOf(item.id) >-1;
});
It can be easily solved with underscore or lodash with something like:
Result = _.filter(MyObject, function (item) {
return _.indexOf(item.id, MyIds) !== -1;
});
I admit, this is a lazy answer. There is probably a way to make it without adding a news library. But lodash is so cool :)
It can be done without jQuery:
var MyIds = [1,2];
var MyObject = [{id:1,size:21,length:31},{id:2,size:22,length:32},{id:3,size:23,length:33}];
var Result = [];
MyObject.forEach(function(element) {
MyIds.forEach(function(id){
if(element.id == id)
Result.push(element);
});
});
A more diverse sollution without using any library:
function find(propName, filters, collection){
var temp = [];
for(var i = 0; i < collection.length; i++){
for(var j = 0; j < filters.length; j++){
if(collection[i][propName] === filters[j]){
temp.push(collection[i]);
break;
}
}
}
return temp;

Deleting Element After Pushing

If I have an array where I am pushing certain elements to a second array- how can I delete those elements from the first array after pushing them to the second? Here is sample code:
for(var a = 0; a < arr.length; a+=1){
if(arr[a].length == 4){
other.push(arr[a]);
}
}
In other words, I know longer want elements arr[a] to be in arr if they have been pushed to other.
Just do a splice on that original array index to remove that element if you no longer require it.
for(var a = 0; a < arr.length;){
if(arr[a].length == 4){
other.push(arr[a]);
arr.splice(a, 1);
}
else {
a += 1;
}
}
This seems fine:
for(var a = 0, length=arr.length; a < length; a++){
if(arr[a].length == 4){
other.push(arr[a]);
arr.splice(a,1);
}
}
Write a function which takes an input array, and a function to determine if an element should be moved. It returns a two-element array, containing the modified input, and the new array into which elements have been extracted.
function extractIf(array, condition) {
return [
array.filter(not(condition)),
array.filter( condition)
];
}
// Specify which elements are to be extracted/moved.
function condition(elt) { return elt.length === 4; }
// Little helper function to invert a function.
function not(fn) { return function() { return !fn.apply(this, arguments); }; }
Invoke this as:
var results = extractIf(arr, condition);
arr = results[0];
other = results[1];
underscore solution
If you are willing to use underscore, you could group the input by the true/false value of the condition:
var groups = _.groupBy(arr, function(elt) { return elt.length === 4; })
Your original array with the elements removed will be in groups.false, and the other array in groups.true.

add elements of an array javascript

Ok, this might be easy for some genius out there but I'm struggling...
This is for a project I'm working on with a slider, I want an array the slider can use for snap points/increments... I'm probably going about this in a mental way but its all good practice! Please help.
var frootVals = [1,2,3,4,5];
var frootInc = [];
for (i=0; i<=frootVals.length; i++) {
if (i == 0){
frootInc.push(frootVals[i]);
}
else{
frootInc.push(frootInc[i-1] += frootVals[i])
}
};
What I'm trying to do is create the new array so that its values are totals of the array elements in frootVals.
The result I'm looking for would be this:
fruitInc = [1,3,6,10,15]
For a different take, I like the functional approach:
var frootVals = [1,2,3,4,5];
var frootInc = [];
var acc = 0;
frootVals.forEach(function(i) {
acc = acc + i;
frootInc.push(acc);
});
var frootVals = [1,2,3,4,5]
, frootInc = [];
// while i < length, <= will give us NaN for last iteration
for ( i = 0; i < frootVals.length; i++) {
if (i == 0) {
frootInc.push(frootVals[i]);
} else {
// rather than frootIne[ i-1 ] += ,
// we will just add both integers and push the value
frootInc.push( frootInc[ i-1 ] + frootVals[ i ] )
}
};
There were a few things wrong with your code check out the commenting in my code example. Hope it helps,
This will do:
var frootVals = [1,2,3,4,5];
var frootInc = [];
for (i=0; i < frootVals.length; i++) { // inferior to the length of the array to avoid iterating 6 times
if (i == 0) {
frootInc.push(frootVals[i]);
}
else {
frootInc.push(frootInc[i-1] + frootVals[i]) // we add the value, we don't reassign values
}
};
alert(JSON.stringify(frootInc));
jsfiddle here: http://jsfiddle.net/f01yceo4/
change your code to:
var frootVals = [1,2,3,4,5];
var frootInc = [frootvals[0]]; //array with first item of 'frootVals' array
for (i=1; i<frootVals.length; i++) {
frootInc.push(frootInc[i-1] + frootVals[i]); //remove '='
}
Here's a very simple pure functional approach (no vars, side-effects, or closures needed):
[1,2,3,4,5].map(function(a){return this[0]+=a;}, [0]);
// == [1, 3, 6, 10, 15]
if you name and un-sandwich the function, you can use it over and over again, unlike a hard-coded var name, property name, or for-loop...

Check if the values of one array are in another

I need to check if array number 2 contains all of the values in array number 1. I am not aware of any method that does this so I developed one that works, I think. Is there a better way to do this, is this a good solution?
var contains = function(a1, a2){
var cCount = 0;
for (var i=0; i<a1.length; i++){
for (var j=0; j<a2.length; j++){
if (a1[i] == a2[j]){
cCount++;
}}}
if (cCount == a1.length){
return true;
}
};
You could check sizes before starting. return false when one is not present instead using a counter. and return true if it reach the end. And use indexof instead looping through a2 every time.
var contains = function(a1, a2){
if (a1.length>a2.length) return false;
for (var i=0; i<a1.length; i++){
if (a2.indexOf(a1[i])<0) return false;
}
return true;
}
just a bit simplified code:
function contains(array1, array2){
var found = false;
for (i in array1) {
for (j in array2) {
if (array1[i] == array2[j]) {
found = true;
}
}
if (!found) return false;
}
return true;
}
another solution I don't really like it but it's shorter...
function contains (arr1, arr2) {
var specialChar = "|"; // Use any char or a sequence that won't exist in values.
var str = specialChar + arr2.join(specialChar) + specialChar;
for (i in arr1) if (str.indexOf(specialChar + arr1[i] + specialChar) == -1) return false;
return true;
}
Your solution is O(n * n) i.e. order n-squared.
You could sort the arrays first and then sequentially check the elements in the sorted arrays for a match. This will give you an O(n log n) solution. Also you can short circuit the check by ensuring that the size of array2 <= the size of array1.
Evidently this only matters if your arrays are sufficiently big.
You can do this in O(n) if you have a 3rd object that you use to keep track of the items that have been seen already. This assumes that the lookup in seen is O(1) (which presumably it is - What's the big O for JavaScript's array when used as a hash?)
var seen = {};
arr2.forEach(function(el) {
seen[el] = true;
});
var allContained = true;
arr1.forEach(function(el) {
if ( allContained && !seen[el] ) {
allContained = false;
}
});
return allContained;
I'd personally use the Array.every() method (though this is, of course, dependent upon a browser that implements this method) in conjunction with Array.indexOf(), which would result in something akin to the following:
var contains = function(needle, haystack){
return needle.every(function(a){
return haystack.indexOf(a) > -1;
});
};
Combining that with the approach you've already produced (testing for browser-support):
var contains = function(needle, haystack){
if ([].every){
return needle.every(function(a){
return haystack.indexOf(a) > -1;
});
}
else {
var result = true;
for (var i = 0, len = needle.length; i < len; i++){
if (haystack.indexOf(needle[i]) === -1) {
return false;
}
}
return result;
}
}
var a1 = [1,2,3],
a2 = [1,2,3,4];
console.log(contains(a1, a2));
JS Fiddle demo.
Note that the else code isn't optimised, it's simply there to demonstrate the code. Having said that, there is a shim for Array.every() at the MDN page (in the references, below) that might make things easier.
References:
Array.prototype.every().
Array.prototype.indexOf().

Shuffle an array as many as possible

I have an array like this
[0,2,3]
The possible shuffling of this array are
[0,2,3], [2,3,0], [3,0,2], [3,2,0], [0,3,2], [2,0,3]
How can I get these combinations? The only idea I have in mind currently is
n = maximum num of possible combinations, coms = []
while( coms.length <= n )
temp = shuffle( original the array );
if temp is there in coms
return
else
coms.push(temp);
But I do not think this is efficient, as here we are blindly depending on uniform distribution of shuffle method.
Is there alternative findings for this problem?
The first thing to note is that the number of permutations increases very fast with regard to the number of elements (13 elements = 6 bilion permutations), so any kind of algorithm that generates them will deteriorate in performance for a large enough input array.
The second thing to note is that since the number of permutations is very large, storing them in memory is expensive, so you're way better off using a generator for your permutations and doing stuff with them as they are generated.
The third thing to note is that recursive algorithms bring a large overhead, so even if you find a recursive solution, you should strive to get a non-recursive one. Obtaining a non-recursive solution if a recursive one exists is always possible, but it may increase the complexity of the code.
I have written a non recursive implementation for you, based on the Steinhaus–Johnson–Trotter algorithm (http://en.wikipedia.org/wiki/Steinhaus%E2%80%93Johnson%E2%80%93Trotter_algorithm)
function swap(arr, a,b){
var temp = arr[a];
arr[a]=arr[b];
arr[b]=temp;
}
function factorial(n) {
var val = 1;
for (var i=1; i<n; i++) {
val *= i;
}
return val;
}
function permute(perm, func){
var total = factorial(perm.length);
for (var j=0, i=0, inc=1; j<total; j++, inc*=-1, i+=inc) {
for (; i<perm.length-1 && i>=0; i+=inc) {
func.call(perm);
swap (perm, i, i+1);
}
func.call(perm);
if (inc === 1) {
swap(perm, 0,1);
} else {
swap(perm, perm.length-1, perm.length-2);
}
}
}
console.clear();
count = 0;
permute([1,2,3,4,5,6], function(){console.log(this); count++;});
console.log('There have been ' + count + ' permutations');
http://jsbin.com/eXefawe/2/edit
Try a recursive approach. Here's a hint: every permutation of [0,2,3] is either
[0] plus a permutation of [2,3] or
[2] plus a permutation of [0,3] or
[3] plus a permutation of [0,2]
As zodiac mentioned the best solution to this problem is a recursive one:
var permute = (function () {
return permute;
function permute(list) {
return list.length ?
list.reduce(permutate, []) :
[[]];
}
function permutate(permutations, item, index, list) {
return permutations.concat(permute(
list.slice(0, index).concat(
list.slice(index + 1)))
.map(concat, [item]));
}
function concat(list) {
return this.concat(list);
}
}());
alert(JSON.stringify(permute([1,2,3])));
Hope that helps.
All permutations of a set can be found by selecting an element in the set and recursively permuting (rearranging) the remaining elements. Backtracking approach can be used for finding the solution.
Algorithm steps (source):
Pseudocode (source):
permute(i)
if i == N output A[N]
else
for j = i to N do
swap(A[i], A[j])
permute(i+1)
swap(A[i], A[j])
Javascript implementation (jsFiddle):
Array.prototype.clone = function () {
return this.slice(0);
};
var input = [1, 2, 3, 4];
var output = [];
function permute(i) {
if (i == input.length)
output.push(input.clone());
else {
for (var j = i; j < input.length; j++) {
swap(i, j);
permute(i + 1);
swap(i, j); // backtrack
}
}
};
function swap(i, j) {
var temp = input[i];
input[i] = input[j];
input[j] = temp;
}
permute(0);
console.log(output);
For an array of length n, we can precompute the number of possible permutations. It's n! (n factorial)
function factorial(n){ return n<=0?1:n*factorial(n-1);}
//There are better ways, but just for illustration's sake
And, we can create a function which maps an integer p between 0...n!-1 to a distinct permutation.
function map(p,orgArr){
var tempArr=orgArr.slice(); //Create a copy
var l=orgArr.length;
var permArr=[];
var pick;
do{
pick=p%l; //mod operator
permArr.push(tempArr.splice(pick,1)[0]); //Remove item number pick from the old array and onto the new
p=(p-pick)/l;
l--;
}while(l>=1)
return permArr;
}
At this point, all you need to do is create an array ordering=[0,1,2,3,...,factorial(n)-1] and shuffle that. Then, you can loop for(var i=0;i<=ordering.length;i++) doSomething(map(ordering[i],YourArray));
That just leaves the question of how to shuffle the ordering array. I believe that's well documented and outside the scope of your question since the answer depends on your application (i.e. is pseudo random good enough, or do you need some cryptographic strength, speed desired, etc...). See How to randomize (shuffle) a JavaScript array? and many others.
Or, if the number of permutations is so large that you don't want to create this huge ordering array, you just have to distinctly pick values of i for the above loop between 0-n!-1. If just uniformity is needed, rather than randomness, one easy way would be to use primitive roots: http://en.wikipedia.org/wiki/Primitive_root_modulo_n
you don't need to recurse. The demo should make the pattern pretty clear: http://jsfiddle.net/BGYk4/
function shuffle(arr) {
var output = [];
var n = arr.length;
var ways = [];
for(var i = 0, j = 1; i < n; ways.push(j *= ++i));
var totalWays = ways.pop();
for(var i = 0; i < totalWays; i++) {
var copy = arr.slice();
output[i] = [];
for(var k = ways.length - 1; k >= 0; k--) {
var c = Math.floor(i/ways[k]) % (k + 2);
output[i].push(copy.splice(c,1)[0]);
}
output[i].push(copy[0]);
}
return output;
}
this should output all possible "shuffles"
console.log(shuffle(['a', 'b', 'c', 'd', 'e']));
this one's cuter (but the output from the other example is much clearer): http://jsfiddle.net/wCnLf/
function shuffle(list) {
var shufflings = [];
while(true) {
var clone = list.slice();
var shuffling = [];
var period = 1;
while(clone.length) {
var index = Math.floor(shufflings.length / period) % clone.length;
period *= clone.length;
shuffling.push(clone.splice(index,1)[0]);
}
shufflings.push(shuffling);
if(shufflings.length == period) return shufflings;
}
}
and of course it still outputs all possible "shuffles"
console.log(shuffle(['a', 'b', 'c', 'd', 'e']));
tibos example above was exactly what I was looking for but I had some trouble running it, I made another solution as an npm module:
var generator = new Permutation([1, 2, 3]);
while (generator.hasNext()) {
snippet.log(generator.next());
}
<script src="http://tjcrowder.github.io/simple-snippets-console/snippet.js"></script>
<script src="http://rawgit.com/bcard/iterative-permutation/master/iterative-permutation.js"></script>
https://www.npmjs.com/package/iterative-permutation
https://github.com/bcard/iterative-permutation

Categories

Resources