How to prevent an array from updating in a for-loop? - javascript

There is an outer array containing many other arrays. I generate the inner arrays an push them to the outer one.
for (i = 0; i < 12; i++) {
if (i == 0) {
var p = [];
for (n = 0; n < 4; n++) {
p.push(n);
}
} else {
s = i % (3);
var b = p[s+1];
p[s+1] = p[s];
p[s] = b;
}
console.log(p);
}
/*OUTPUT:
Array(4) [ 0, 1, 2, 3 ]
tsp.js:45:17
Array(4) [ 0, 2, 1, 3 ]
tsp.js:45:17
Array(4) [ 0, 2, 3, 1 ]
tsp.js:45:17
Array(4) [ 2, 0, 3, 1 ]
tsp.js:45:17
Array(4) [ 2, 3, 0, 1 ]
tsp.js:45:17
Array(4) [ 2, 3, 1, 0 ]
tsp.js:45:17
Array(4) [ 3, 2, 1, 0 ]
tsp.js:45:17
Array(4) [ 3, 1, 2, 0 ]
tsp.js:45:17
Array(4) [ 3, 1, 0, 2 ]
tsp.js:45:17
Array(4) [ 1, 3, 0, 2 ]
tsp.js:45:17
Array(4) [ 1, 0, 3, 2 ]
tsp.js:45:17
Array(4) [ 1, 0, 2, 3 ]
*/
This code outputs as expected a lot of different arrays. But this one outputs one array containing the same array over and over again:
o = [];
for (i = 0; i < 12; i++) {
if (i == 0) {
var p = [];
for (n = 0; n < 4; n++) {
p.push(n);
}
} else {
s = i % (3);
var b = p[s+1];
p[s+1] = p[s];
p[s] = b;
}
o.push(p);
}
console.log(o);
/*
OUTPUT:
(12) […]
0: Array(4) [ 1, 0, 2, … ]
1: Array(4) [ 1, 0, 2, … ]
2: Array(4) [ 1, 0, 2, … ]
3: Array(4) [ 1, 0, 2, … ]
4: Array(4) [ 1, 0, 2, … ]
5: Array(4) [ 1, 0, 2, … ]
6: Array(4) [ 1, 0, 2, … ]
7: Array(4) [ 1, 0, 2, … ]
8: Array(4) [ 1, 0, 2, … ]
9: Array(4) [ 1, 0, 2, … ]
10: Array(4) [ 1, 0, 2, … ]
11: Array(4) [ 1, 0, 2, … ]
length: 12
<prototype>: Array []
tsp.js:47:13
*/
I expected that the second code outputs all the different arrays from the for loop packed in one array, but it doesn't.

When you do o.push(p); you're pushing a reference of p into your array. This means at each iteration of your loop when you modify the elements in p, the elements at your reference change, thus changing the array within your o array.
Thus, you need to make unique references to your p arrays before pushing them into your o array. One way to do this is using .slice() to make a copy of your array like so:
var o = [];
for (var i = 0; i < 12; i++) {
if (i == 0) {
var p = [];
for (var n = 0; n < 4; n++) {
p.push(n);
}
} else {
var s = i % (3);
var b = p[s + 1];
p[s + 1] = p[s];
p[s] = b;
}
o.push(p.slice()); // copy the elements in p to a new array, such that the array is now it's own unique reference in memory
}
console.log(o);

One problem with both examples, is that you declare p in the if branch, but reference it in the else branch and in the enclosing scope.
Try moving it to the start of the function:
for (i = 0; i < 12; i++) {
var p = [];
if (i == 0) {
or
var p = [];
for (i = 0; i < 12; i++) {
if (i == 0) {
Depending on which meets your requirements

You're declaring var p = []; inside the loop which seems to be working because it is a javascript, but very confusing. Move it to the upper lever near the o = [];
the problem you're facing is because you're pushing the reference to an array and not just values. You need to copy values to a new array before doing a o.push();
var o = [];
var p = [];
for (i = 0; i < 12; i++) {
if (i == 0) {
for (n = 0; n < 4; n++) {
p.push(n);
}
} else {
s = i % (3);
var b = p[s + 1];
p[s + 1] = p[s];
p[s] = b;
}
var copy = [];
for (j = 0; j < p.length; j++) {
copy.push(p[j]);
}
o.push(copy);
}
console.log(o);

Related

Chunk an array of objects and add empty arrays at the end

I need to chunk an array of objects so i write:
function conditionalChunk(array, size, rules = {}) {
let copy = [...array],
output = [],
i = 0;
while (copy.length)
output.push(copy.splice(0, rules[i++] ?? size))
return output
}
and it works fine if I have rules like { 0: 2, 1: 2 }
const input = [[1,2,3],[4,5,6,7]],
output = conditionalChunk(input.flat(), 3, { 0: 2, 1: 2 });
// OUTPUT: [[1,2],[3,4],[5,6,7]]
but when I have rules at the end like { 0: 2, 1: 2, 2:0, 5:0 } my function ignore to create empty arrays at the end.
the output I need is:
const input = [[1,2,3],[4,5,6,7]],
output = conditionalChunk(input.flat(), 3, { 0: 2, 1: 2, 2:0, 5:0 });
// OUTPUT: [[1,2],[3,4],[],[5,6,7],[]]
so I just need to not ignore rules for empty arrays at the end of array. How I can do that?
Finally, you could check the keys of rules and if greater or equal to the next index of output push an empty array.
function conditionalChunk(array, size, rules = {}) {
let output = [],
i = 0;
while (i < array.length)
output.push(array.slice(i, i += rules[output.length] ?? size));
let l = Object.keys(rules).reduce((l, v) => l + (v >= output.length), 0);
while (l--) output.push([]);
return output;
}
console.log(conditionalChunk([1, 2, 3, 4, 5, 6, 7], 3, { 0: 2, 1: 2 })); // [[1,2],[3,4],[5,6,7]]
console.log(conditionalChunk([1, 2, 3, 4, 5, 6, 7], 3, { 0: 2, 1: 2, 2: 0, 5: 0 })); // [[1,2],[3,4],[],[5,6,7],[]]
console.log(conditionalChunk([1, 2, 3, 4, 5, 6, 7], 3, { 0: 0, 1: 2, 8: 0, 7: 0, 9:0, 20:0 }));
.as-console-wrapper { max-height: 100% !important; top: 0; }
maybe you can try this, I prefer for...each loop in place of a while.
function conditionalChunk(array, size = 1, rules = {}) {
let copy = [...array],
output = [],
i = 0;
for (const rule of Object.keys(rules)) {
let val = copy.splice(0, rules[rule] || size);
if (typeof val === 'undefined') val = [];
output.push(val);
}
return output;
}
var results = conditionalChunk([1, 2, 3, 4, 5], 2, { 0:2, 1: 2, 2:2, 3:0 });
console.log(results, '::results::');
https://jsfiddle.net/5ozbj7na/
A solution to your problem would be to add this bit of code after the while loop before the return statement
output.length = Math.max.apply(null, [output.length, ...Object.keys(rules)]) || output.length;
for (r in rules)
{
output[r] = new Array(rules[r]);
}
It just extends the output array to the desired length then populates required spots with empty arrays (sorry for the complicated first line but JavaScript is complicated so :| ...)
Please try this one, this should work for you and is done based on your solution, so it should be easier to understand
function conditionalChunk(array, size, rules = {}) {
let copy = [...array],
output = [],
i = 0;
while (copy.length) output.push(copy.splice(0, rules[i++] ?? size));
const arr = Object.keys(rules).filter((key) => key > i);
arr.forEach((key) => {
if (rules[key] === 0) output.push([]);
});
return output;
}

Why the push to "r" array not working properly in the loop?

Why the following array doesn't push correctly in the loop to r?
If I change to if((pivot + originArr[c]) <= 5) instead of if((pivot + originArr[c]) <= 3)
My result is wrong:
[ [ 0, 1, 2, 3, 4 ],
[ 0, 1, 2, 3, 4 ],
[ 0, 1, 2, 3, 4 ],
[ 0, 2, 3 ],
[ 1, 2, 3 ] ]
Expected result should be[ [ 0, 1, 2], [ 0, 1, 3], [ 0, 1, 4], [ 0, 2, 3 ] ]
If r is not empty, it will recursive and send the first iteration result to the function to do computation until the "r" is empty. It doesn't push individual group of array to "r" for every c loop.
var data = [0, 1, 2, 3, 4, 5];
function compute(originArr, filterArr) {
var r = [];
var arr;
let firstLoop = false;
if (filterArr.length == 0) {
firstLoop = true;
arr = originArr;
} else {
arr = filterArr;
}
arr.forEach(function(i, index) {
var pivot;
if (firstLoop) {
pivot = index;
} else {
pivot = parseInt(i.slice(-1));
}
var nextIndex = pivot + 1;
console.log(pivot, nextIndex);
for (var c = nextIndex; c < originArr.length; c++) {
let tempResult = [];
console.log(c);
if (pivot + originArr[c] <= 3) {
if (firstLoop) {
tempResult.push(index);
} else {
tempResult = i;
}
tempResult.push(c);
console.log(tempResult);
r.push(tempResult); // suppose to push [0,1], [0,2], [0,3], [1,2] for the first iteration
}
}
});
if (r.length > 0) {
return compute(originArr, r);
} else {
return arr;
}
}
console.log(compute(data, []));
//Final result should be [[0,1,2]]
I think I found out the problem.
We can't clone the array like this
tempResult = i;
it will affect the reference 'i' after I have pushed the new number into the temResult.
So my solution is to change the cloning way to:
tempResult = [...i];
That cloning will not affects the reference.

Filtering Arrays in Javascript [duplicate]

This question already has answers here:
How to get the difference between two arrays in JavaScript?
(84 answers)
Closed 6 years ago.
Say I have the following two arrays:
var arrOne = [1, 4, 7];
var arrTwo = [1, 2, 3, 4, 5];
var arrThree = [];
I'd like to itterate over arrTwo and if it contains an element that is also in arrOne, remove it from arrTwo, and insert it in arrThree. So looking at the above arrays the state of the arrays afterwards should look like this:
var arrOne = [1, 4, 7];
var arrTwo = [2, 3, 5];
var arrThree = [1, 4];
Could anyone point me in the right direction and the best way to go about this? If code is provided, a step-by-step explanation would really be appreciated so that I can understand what's going on.
A simple for loop, matching with indexOf and splicing matches.
var arrOne = [1, 4, 7];
var arrTwo = [1, 2, 3, 4, 5];
var arrThree = [];
for (var i = 0; i < arrTwo.length; i++) {
if (arrOne.indexOf(arrTwo[i]) >= 0) {
arrThree.push(arrTwo[i]);
arrTwo.splice(i, 1);
i--;
}
}
console.log(arrOne, arrTwo, arrThree)
Array.IndexOf
Array.splice
Look into the Underscore library. All the elements in arrOne that are also in arrTwo is called _.intersection().
Use simple while loop with Array#splice and Array#unshift methods.
var arrOne = [1, 4, 7];
var arrTwo = [1, 2, 3, 4, 5];
var arrThree = [];
// get length of array
var l = arrTwo.length;
// iterate over array from the end
while (l--) {
// check value present in arrOne
if (arrOne.indexOf(arrTwo[l]) > -1)
// if present then remove and insert it
// at the beginning of arrThree
arrThree.unshift(arrTwo.splice(l, 1)[0])
}
console.log(arrTwo, arrThree);
Hi You can use filter function to filter array.
try with below code.
var arrOne = [1, 4, 7];
var arrTwo = [2, 3, 5, 1];
var arrThree = [];
function checkValue(a) {
return !arrOne.indexOf(a);
}
function checkValue2(a) {
return arrThree.indexOf(a);
}
function myFunction() {
arrThree = arrTwo.filter(checkValue);
document.getElementById("demo").innerHTML = arrThree ;
arrTwo = arrTwo.filter(checkValue2);
document.getElementById("demo1").innerHTML = arrTwo;
}
var arrOne = [1, 4, 7];
var arrTwo = [1, 2, 3, 4, 5];
var arrThree = diff(arrOne,arrTwo);//passes the two arrays
console.log(arrThree);
function diff(one, two){
one.forEach(function(e1){ //iterate through the first array
two.forEach(function(e2){//iterate through second
if(e1 == e2) //checking if elements are equal
two.pop(e2);//removing from second array
});
});
return two; //returning new array
}
You can use underscore js for easy array operations, the difference operation will be _.difference([1, 2, 3, 4, 5], [5, 2, 10]);.
var array1 = [1, 2, 3, 4, 5, 6],
var array2 = [1, 2, 3, 4, 5, 6, 7, 8, 9];
var common = $.grep(array1, function(element) {
return $.inArray(element, array2) !== -1;
});
console.log(common); // returns [1, 2, 3, 4, 5, 6];
array2 = array2.filter(function(obj) {
return array1.indexOf(obj) == -1;
});
// returns [7,8,9];
Since the arrays are sorted you could read them in parallel : O(n) instead of O(n2). Don't use a library for such a simple problem, this is overkill :-)
var i = 0, j = 0;
var a = [1, 4, 7];
var b = [1, 2, 3, 4, 5];
var c = [];
while (i < a.length && j < b.length) {
if (a[i] < b[j]) i++;
else if (a[i] > b[j]) j++;
else c.push(b.splice(j, 1)[0]);
}
console.log("a " + toString(a));
console.log("b " + toString(b));
console.log("c " + toString(c));
function toString (v) {
return "[ " + v.join(" ") + " ]";
}
Trace :
#0 init
a = [ 1 4 7 ]
i
b = [ 1 2 3 4 5 ]
j
c = []
#1 a[i] = b[j] => move b[j] to c
a = [ 1 4 7 ]
i
b = [ 2 3 4 5 ]
j
c = [ 1 ]
#2 a[i] < b[j] => increment i
a = [ 1 4 7 ]
i
b = [ 2 3 4 5 ]
j
c = [ 1 ]
#3 a[i] > b[j] => increment j
a = [ 1 4 7 ]
i
b = [ 2 3 4 5 ]
j
c = [ 1 ]
#4 a[i] > b[j] => increment j
a = [ 1 4 7 ]
i
b = [ 2 3 4 5 ]
j
c = [ 1 ]
#5 a[i] = b[j] => move b[j] to c
a = [ 1 4 7 ]
i
b = [ 2 3 5 ]
j
c = [ 1 4 ]
#6 a[i] < b[j] => increment i
a = [ 1 4 7 ]
i
b = [ 2 3 5 ]
j
c = [ 1 4 ]
#7 a[i] > b[j] => increment j
a = [ 1 4 7 ]
i
b = [ 2 3 5 ]
j
c = [ 1 4 ]
#8 j = length of b => done

How would I append all the combinations in a list?

var combinations = function(numArr, choose, callback) {
var n = numArr.length;
var c = [];
var inner = function(start, choose_) {
if (choose_ == 0) {
callback(c);
} else {
for (var i = start; i <= n - choose_; ++i) {
c.push(numArr[i]);
inner(i + 1, choose_ - 1);
c.pop();
}
}
}
inner(0, choose);
}
I'm not entirely sure how I would append all the items inside an array after it's done creating all the combinations.
I attempted some modifications to the code though I ultimately ended up messed it up.
Example :
So, are you trying to do something like this: http://www.geeksforgeeks.org/print-all-possible-combinations-of-r-elements-in-a-given-array-of-size-n/
I found a double-loop implementation accomplishes the task pretty well:
function findCombinations(nums, cb) {
var allCombinations = [];
var maxIndex = nums.length - 1;
var i = 0, j = 0;
for (i; i <= maxIndex; i += 1) {
for (j = i; j <= maxIndex; j += 1) {
if (i !== j) {
allCombinations.push([ nums[i], nums[j] ]);
}
}
}
cb(allCombinations);
}
findCombinations([1, 2, 3, 4], function (combinations) {
console.log(combinations);
});
Prints the output:
[ [ 1, 2 ], [ 1, 3 ], [ 1, 4 ], [ 2, 3 ], [ 2, 4 ], [ 3, 4 ] ]
Were you specifically trying to implement a recursion tree?
If this is the right output, I got it to work with a minor fix to your solution.
Your approach is totally correct. You just need to think about when you're beginning/ending
a combination. When a combination ends you need to push the current combination to an external array.
Your base case signifies when a combination is complete, at this point you need to push a COPY of the current combination.
> combinations([0,1,2,3],2)
[ [ 0, 1 ],
[ 0, 2 ],
[ 0, 3 ],
[ 1, 2 ],
[ 1, 3 ],
[ 2, 3 ] ]
> combinations([0,1,2,3],3)
[ [ 0, 1, 2 ],
[ 0, 1, 3 ],
[ 0, 2, 3 ],
[ 1, 2, 3 ] ]
Here is the tweaked solution. You could use the callback on c if you'd like.
function combinations(numArr, choose, callback) {
var n = numArr.length;
var c = [];
var temp = [];
var inner = function(start, choose_) {
if (choose_ === 0) {
c.push(temp.slice());
} else {
for (var i = start; i <= n - choose_; i++) {
temp.push(numArr[i]);
inner(i + 1, choose_ - 1);
temp.pop();
}
}
}
inner(0, choose);
return c;
}

Javascript getting the oldest element in the array

Lets say that I am to remove the oldest element of an array, because I wanted to replace it with a new value. (first-in-first-out).
For example, I have this array of values
var arr = [1,2,3,4,5,6,7]
And I wanted to only get the first three, values, and then on the 4th, replace the element who came first
[1,2,3], [4,2,3], [4,5,3] and so on..
I came up with a solution
var arr = [1,1,2,3,4,5,6,7];
var newArr = [];
for(i=0; i<arr.length; i++){
if(newArr.length == 3 && newArr.indexOf(arr[i]) < 0) {
newArr[i%3] = arr[i];
} else if(newArr.indexOf(arr[i]) < 0) {
newArr.push(arr[i])
}
console.log(newArr)
}
Which will render:
1
1
1,2
1,2,3
1,4,3
1,4,5
6,4,5
6,7,5
Instead of
1
1,2
1,2,3
4,2,3
4,5,3
4,5,6
7,5,6
What am I missing out.
var arr = [1, 1, 2, 3, 4, 5, 6, 7];
var newArr = [], currentIndex = 0;
for (i = 0; i < arr.length; i++) {
if (newArr.length === 3 && newArr.indexOf(arr[i]) < 0) {
newArr[currentIndex % 3] = arr[i];
currentIndex += 1;
} else if (newArr.indexOf(arr[i]) < 0) {
newArr.push(arr[i]);
}
console.log(newArr)
}
Output
[ 1 ]
[ 1 ]
[ 1, 2 ]
[ 1, 2, 3 ]
[ 4, 2, 3 ]
[ 4, 5, 3 ]
[ 4, 5, 6 ]
[ 7, 5, 6 ]
You just need to track the current index where you need to place the number using a separate variable.

Categories