Why is my Javascript for loop not looping? - javascript

I'm trying to write a for loop that splits an array (parameter: arr) into sub-arrays of a given size (parameter: size), but it seems to be exiting the for loop early/not actually looping back in.
This code should return [['a', 'b'] ['c', 'd']], but right now is only returning [['a', 'b']].
I've tried researching but I can't pinpoint what in my code is stopping the loop from going back through the array.
function chunkArrayInGroups(arr, size) {
var newArr = [
[]
];
for (var i = 0; i < arr.length; i++) {
newArr[0].push(arr.shift(arr.slice(i, size)));
}
return newArr;
}
//calling the function:
console.log(chunkArrayInGroups(['a', 'b', 'c', 'd'], 2));
Please help me figure this out.

You could use a while loop and check the position against the length of the array.
function chunkArrayInGroups(array, size) {
var result = [],
i = 0;
while (i < array.length) {
result.push(array.slice(i, i += size));
}
return result;
}
console.log(chunkArrayInGroups(['a', 'b', 'c', 'd'], 2));
.as-console-wrapper { max-height: 100% !important; top: 0; }

In the for loop increment i with size. On each iteration slice an array of length size (between i and i + size), and push it to newArr:
function chunkArrayInGroups(arr, size) {
var newArr = [];
for (var i = 0; i < arr.length; i += size) {
newArr.push(arr.slice(i, i + size));
}
return newArr;
}
//calling the function:
console.log(chunkArrayInGroups(['a', 'b', 'c', 'd'], 2));

You're modifying the array while you're looping over it, because arr.shift() removes the first element from the array and returns that. You're pushing that removed element onto newArr[0], not the slice.
So on the first iteration of the loop, arr is:
['a', 'b', 'c', 'd']
You push 'a' onto the result array, remove it from arr, and increment i.
On the next iteration, arr is
['b', 'c', 'd']
You push 'b' onto the result array, remove it from arr, and increment i.
On the next iteration, arr is
['c', 'd']
i is now 2, which is not less than arr.length, so the loop ends.
There's no reason to use arr.shift(), just use arr.slice() to get the chunks. You need to iterate by the chunk size, not 1. And the second argument to slice() is the end position (non-inclusive), not the size, so you need to add i + size.
function chunkArrayInGroups(arr, size) {
var newArr = [
[]
];
for (var i = 0; i < arr.length; i += size) {
newArr[0].push(arr.slice(i, i+size));
}
return newArr;
}
//calling the function:
console.log(chunkArrayInGroups(['a', 'b', 'c', 'd'], 2));

Related

Changing array position in javascript

I want to move to the part I want in the array [a, b, c, d, e, f]. For example, how do you move b with index 1 to e?
The array I want is:
[a, c, d, e, b, f]
You can use .splice()
.splice first argument is the start position where you want to delete. The second argument is how many elements you want to delete. Then the rest of arguments are elements you want to append at the deleted element index.
const array = ['a', 'b', 'c', 'd', 'e', 'f'];
// Delete element and save it to a variable
const el = array.splice(1, 1);
// Add deleted element to the required position
array.splice(4, 0, el[0]);
console.log(array);
I think you can object destructure to create what you are looking for. Though, I am not sure if this is the best way you can do it.
const a = ['a', 'b', 'c', 'd', 'e', 'f']
// I would just create a new array that would work like this
const newA = [
// everything before index 1
...a.slice(0, 1),
// everything after index 1 till index 4 and then the index 1
...[...a.slice(1+1,4+1), a[1]],
// everything after index 4
...a.slice(4+1)
]
console.log(newA)
You can use temp variable for temporary store data and loop from your wanted move index to target index
var d = ['a', 'b', 'c', 'd', 'e', 'f'];
function moveTo(data, from, to) {
let _tmp = data
let _move = data[from]
for(var i = from; i <= to; i++) {
if(i === to) _tmp[i] = _move
else _tmp[i] = data[i+1]
}
data = _tmp
}
moveTo(d, 1, 4)
console.log(d)
Using Array.splice:
This gives us an array containing just the element from the index you give:
arr.splice(from, 1)
We then insert this at the chosen index (Using the spread operator to expand the array)
arr.splice(to, 0, ...arr.splice(from, 1))
let arr = ['a', 'b', 'c', 'd', 'e', 'f'];
function moveElement (targetArray, from, to) {
targetArray.splice(to, 0, ...targetArray.splice(from, 1))
}
moveElement(arr, 1, 4);
console.log(arr);

How do I return the similar values between 2 arrays, and in the order of the second?

I have 2 arrays. I am trying to return the similar values between the 2 but in the order of the second. For example, take a look at the two arrays:
array1 = ['a', 'b', 'c']
array2 = ['b', 'c', 'a', 'd']
What I would like to return is this:
sim = ['b', 'c', 'a']
Here is a link to what I am trying to accomplish. Currently the script is faulty and not catching the corner case.
You could use a Set for array1 use Array#filter array2 by checking the set.
var array1 = ['a', 'b', 'c'],
array2 = ['b', 'c', 'a', 'd'],
theSet = new Set(array1),
result = array2.filter(v => theSet.has(v));
console.log(result);
Some annotations to your code:
function arr_sim (a1, a2) {
var //a = {}, // take an object as hash table, better
a = Object.create(null), // a really empty object without prototypes
sim = [],
i; // use single declaration at top
for (i = 0; i < a1.length; i++) { // iterate all item of array 1
a[a1[i]] = true;
}
for (var i = 0; i < a2.length; i++) {
if (a[a2[i]]) {
sim.push(a2[i]); // just push the value
}
}
return sim;
}
console.log(arr_sim(['a', 'b', 'c'], ['b', 'c', 'a', 'd']));
You can iterate array2 with a filter, and check if the value is contained in array1:
let array1 = ['a', 'b', 'c'];
let array2 = ['b', 'c', 'a', 'd'];
let sim = array2.filter((entry) => {
return array1.includes(entry);
});
console.log(sim);
I think this is what you are looking for?
function arr_sim (a1, a2) {
a1 = Array.isArray(a1)?a1:typeof a1 == "string"?a1.split(""):false;
a2 = Array.isArray(a2)?a1:typeof a2 == "string"?a2.split(""):false;
if(!a1 || !a2){
alert("Not valid values");
return;
}
var filterArray = a1.filter(function(val){
return a2.indexOf(val) !== -1;
})
return filterArray;
}
console.log(arr_sim(['a', 'b'], ['b', 'a', 'c', 'd']));
console.log(arr_sim("abcd", "abcde"));
console.log(arr_sim("cxz", "zcx"));
Try this
const arr_sim = (a1, a2) => a2.filter(a => a1.includes(a))
console.log(arr_sim(['a', 'b', 'c'], ['b', 'c', 'a', 'd']));
try this example here similar-values betwe
en two arrays
var a1 = ['a' ,'b'];
var a2 = ['a' ,'b' ,'c'];
var result = arr_sim(a1,a2);// call method arr_sim
console.log(result);
function arr_sim (a1, a2) {
var similar = [];
for( var i = 0 ; i <a1.length ; i++ ){ // loop a1 array
for( var j = 0 ; j <a2.length ; j++ ){ // loop a2 array
if( a1[i] == a2[j] ){ // check if is similar
similar.push(a1[i]); // add to similar array
break; // break second loop find that is similar
} // end if
} // end second lopp
} // end first loop
return similar; // return result
} // end function

Trying to split array into specified amount of subarrays in javascript

I'm writing a function that takes an array and a number parameter and returns the number amount of arrays split from the given array. So the call chunkArrayInGroups(["a", "b", "c", "d"], 2); should return [a,b] [c,d]. My code is returning [a,c] [b,d]. It should be an easy solution, but I still can't figure out.
function chunkArrayInGroups(arr, size) {
// Break it up.
var newarr=[];
var amount=0;
if(arr.length%2===0)
{
amount=arr.length/size;
}
else
amount=(arr.length/size)+1;
console.log(amount);
for(i=0;i<amount;i++)
{
newarr[i]=[];
}
console.log(newarr);
for(z=0;z<arr.length;z=z+size)
{
for(x=0;x<size;x++)
{
newarr[x].push(arr[z+x]);
}
}
console.log(newarr);
}
chunkArrayInGroups(["a", "b", "c", "d"], 2);
Also, if you see bad syntax please correct me, I'm used to writing Java. Thank you!
Run over all the items in the array, and whenever the index % size is 0, add another sub array, then push the item to the last sub array.
function chunkArrayInGroups(arr, size) {
var chunks = [];
for(var i = 0; i < arr.length; i++) {
if(i % size === 0) {
chunks.push([]);
}
chunks[chunks.length - 1].push(arr[i]);
}
return chunks;
}
console.log('Size 2', JSON.stringify(chunkArrayInGroups(['a', 'b', 'c', 'd'], 2)));
console.log('Size 3', JSON.stringify(chunkArrayInGroups(['a', 'b', 'c', 'd'], 3)));
console.log('Size 4', JSON.stringify(chunkArrayInGroups(['a', 'b', 'c', 'd'], 4)));
console.log('Size 6', JSON.stringify(chunkArrayInGroups(['a', 'b', 'c', 'd'], 6)));
You could use the Array.slice method together with the loop to chunk an array:
function chunkArrayInGroups(arr, size) {
let i,j,res = [];
for (i=0,j=arr.length; i<j; i+=size) {
res.push(arr.slice(i,i+size));
}
return res;
}
console.log(chunkArrayInGroups(["a", "b", "c", "d"], 2));
The issue comes from newarr[x].push(arr[z+x]);.
Each time the second loop runs, it adds 1 letter to the first array inside newarr and 1 letter to the second array inside newarr.
This is because x inside the loop (in the case of size = 2), starts as 0 (the first array) and then becomes 1 (the second array).
To fix this problem:
newarr[x].push(arr[z+x]); should be changed to newarr[z/size].push(arr[z+x]);
This would be my solution;
function chunkArrayInGroups(a,n){
return n > 0 ? n <= a.length ? a.reduce((r,e,i) => (r[Math.floor(n*i/a.length)].push(e),r), Array(n).fill().map(_ => [])) : a : a;
}
var a = ["a", "b", "c", "d","e"],
n = 3;
result = chunkArrayInGroups(a,n);
console.log(result);
Beside the given answers, you could use another approach with Array#reduce and check if you need a new array for a new chunk.
function chunkArrayInGroups(array, size) {
return array.reduce(function(r, a, i, aa) {
i % Math.ceil(aa.length / size) || r.push([]);
r[r.length - 1].push(a);
return r;
}, []);
}
console.log(chunkArrayInGroups(["a", "b", "c", "d", "e"], 3));

Reduce the size/length of an array to a certain size/length

I have an array: var array = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i']
I want the array to be a length of 3, but I don't want to remove the consecutive elements. I want to remove elements evenly from an array.
Since array.length is 9, I want to remove 6 elements from it and I always want to keep the first element. so in this case, var array would be like ['a', 'e', 'i']
I was doing like this so far:
var extraLength = array.length - 3;
var eachVal = Math.round(array.length/extraLength);
for (var j = 0; j < extraLength; j++){
for(var i = array.length -1; i >= 0; i-- ) {
if (i == eachVal*j && i != 0) {
array.splice(i, 1)
}
}
}
This gives an error saying array.splice is not a function.
Also, as I write this, I realized that this only works when array.length/extraLength is an even number, so in the example above, it does not work.
How can I achieve this?
This gives an error saying array.splice is not a function.
There is no error, at least with the code you presented in the question. See the snippet below for the result of your code:
var array = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i'];
var extraLength = array.length - 3;
var eachVal = Math.round(array.length/extraLength);
for (var j = 0; j < extraLength; j++){
for(var i = array.length -1; i >= 0; i-- ) {
if (i == eachVal*j && i != 0) {
array.splice(i, 1)
}
}
}
console.log(array);
I want the array to be a length of 3, but I don't want to remove the
consecutive elements. I want to remove elements evenly from an array.
Since array.length is 9, I want to remove 6 elements from it and I
always want to keep the first element. so in this case, var array
would be like ['a', 'e', 'i']
But, this only one use-case. How do you want to handle odd/even sized arrays? I assume, your basic requirement is to remove elements with some delta based on the length of the array and the desired resulting size. And you would be fine by truncating the trailing elements.
To do that would be easy by dividing the length of the array by your desired size and flooring it to avoid fractions. Adding one to that will allow you to have a delta step factor which is suitable for odd sized arrays.
Once done that, you just iterate the array with a step size of your calculated delta factor.
Example:
var array = [
['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i'],
['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h'],
['a', 'b', 'c', 'd', 'e']
],
factor, result, desiredSize = 3;
for (i=0; i < array.length; i++) {
// calculate the delta factor
factor = Math.floor(array[i].length / desiredSize) + 1;
factor = (desiredSize % 2 === 0) ? --factor : factor;
result = [];
// iterate with the step size of the calculated facor
for (j = 0; j < array[i].length; j = j + factor) {
result.push(array[i][j]);
}
console.log(result);
}
In the above example, I am using a nested array to show multiple arrays of differing lengths to keep the code size compact. Check the console to see the result for each of the arrays.
Edit:
Changed the code to take into account if the desiredSize is an even number. Have to just rollback the increment on the floored delta factor. This will make it more evenly distributed. Thank you #Andrey Popov for the comment.

Find all the combinations for each element in mutliple arrays

I have the following object
var mapping = {
0: ['A','B','C'],
1: ['D','E','F'],
2: ['G', 'H', 'I'],
---
---
9: ['X','Z']
}
There is a function that references the above object and finds all the possible combinations. For example, we have
function combination(value){}
combination([1,0]); // DA, DB, DC, EA, EB, EC, FA, FB, FC
So in the above invocation the keys at "1" and "0" from the map object will be referenced and all the possible combinations for those two will be returned.
I think the best way to solve this would be to use a recursion, but i just can't seem to wrap my head around this
Not just recursion you can use multiple for loops to achieve this
for (var i = 0 ; i < mapping[index1].length ; i++)
{
for (var j = 0 ; j < mapping[index2].length ; j++)
{
resultArray.push(mapping[i][j]);
}
}
here resultArray is the output array, index1, index2 are the indexes passed
Close enough:
var mapping = {
0: ['A', 'B', 'C'],
1: ['D', 'E', 'F'],
2: ['G', 'H', 'I'],
9: ['X', 'Z']
}
function combine(array, index1, index2) {
var result = array[index1].map(function (el1) {
return array[index2].map(function (el2) {
return [el1, el2].join('');
})
});
return [].concat.apply([], result);
}
function combineAll(array, indices) {
var result = [];
for (var i = 0; i < indices.length - 1; i++) {
var index = indices[i];
var nextIndex = indices[i + 1];
result = result.concat(combine(array, index, nextIndex));
}
return result;
}
var combinations = combineAll(mapping, [1, 0, 9]);
console.log(combinations);
document.write(JSON.stringify(combinations, null, 2));
To find all possible combination we have to iterate over mapping object as well as array corresponding to given key, here i create two functions combination which will iterate over mapping object keys and map which will iterate of array corresponding to each given key:
var mapping = {
0: ['A','B','C'],
1: ['D','E','F'],
2: ['G', 'H', 'I'],
3: ['J', 'K', 'L'],
4: ['M', 'N', 'O']
}
var resultArray = [];
function combination(x){
for(var i=0;i<x.length;i++){
for(var j=i+1;j<x.length;j++){
map(x[i],x[j])
}
}
}
function map(index1,index2){
for (var i in mapping[index1])
{
if(mapping[index1].hasOwnProperty(i)){
for (var j in mapping[index2])
{
if(mapping[index2].hasOwnProperty(j)){
resultArray.push(mapping[index1][i]+''+mapping[index2][j]);
}
}
}
}
}
combination([0,2,1,4])
console.log(resultArray);
You can use recursion in order to solve this problem.
Simply iterate through the indices, and try to add every corresponding item recursively.
I have implemented a working JS function for you:
function combination(o) { // just a wrapper for convenient usage
var current = [];
function step() { // recursive function
if (current.length === o.indices.length) { // combination is ready
o.callback(current); // callback
return; // and leave recursion
}
// current.length is a current position (0, 1, 2, 3 etc.) for which we find a value
// o.indices[o.current.length] is an index of mapping for current position (0, 2, 2, 1 in a demo below)
// o.mapping[o.indices[o.current.length]] is simply a row
o.mapping[o.indices[current.length]].forEach(function(x) {
current.push(x);
step();
current.pop();
});
}
step(); // start recursion
}
You can use it this way:
combination({
mapping: { // your mapping
0: ['A', 'B', 'C'],
1: ['D', 'E', 'F'],
2: ['G', 'H', 'I']
},
indices: [0, 2, 2, 1], // indices may repeat
callback: function(x) { // callback will be called every time we find a combination
document.body.innerHTML += x + "<br/>"; // x is an array
}
});
Here is the working JSFiddle demo.
Following is a solution using recursion.
It does a DFS (Depth First Traversal ) to find all the paths of length corresponding to the input array.
For every dive to the next level, the array gets shortened using slice(1). The original array is not modified and the pattern repeats. When there are no more elements in the array, the path is printed.
I have added a count to see how many combinations are generated. The count should be a product of the lengths of all arrays in the initial input array.
That is for snippet with input array [2,0,3,7] , the product is 3 * 3 * 4 * 3 = 108, i.e 108 combinations.
Essentially picture a tree with the first level nodes with all mapping[2] elements, each of those have mapping[0] children making level 2 of the tree, each level 2 then has mapping[3] elements as children at level 3 and finally mapping[7] would make up the leaf nodes of the tree. This can go to any level based on your input array and your mapping configuration.
The code below does a recursive traversal of the above tree, each time going from root to each leaf node and prints out that path.
var mapping = {
0: ['0A','0B','0C'],
1: ['1A','1B','1C'],
2: ['2A','2B','2C'],
3: ['3A','3B','3C', '3D'],
4: ['4A','4B','4C'],
5: ['5A','5B','5C'],
6: ['6A','6B','6C'],
7: ['7A','7B','7C']
}
var count = 0;
function traverse(arr, comb) {
if(!arr.length) {
console.log(++count + " : " + comb+"\n");
return;
}
for(var j =0; j < mapping[arr[0]].length; j++)
traverse(arr.slice(1), comb + " " + mapping[arr[0]][j]);
}
traverse([2,0,3,7],"");

Categories

Resources