Chunk Array into groups - what's wrong with my code? - javascript

Below is the code :
function chunkArrayInGroups(arr, size) {
// Break it up.
var newArr =[];
for(var i = 0;i < arr.length;i++){
for(var j = 0;j < size;j++){
newArr.push(arr.splice(0,size));
}
}
var result = [];
for(i = 0;i < newArr.length;i++){
if(newArr[i].length != 0){
result.push(newArr[i]);
}
}
return result;
}
chunkArrayInGroups([0, 1, 2, 3, 4, 5, 6, 7,8], 2);
This should return - [[0, 1], [2, 3], [4, 5], [6, 7], [8]]. However, the code returns [[0, 1], [2, 3], [4, 5], [6, 7]]. Also, if my input array is ([0,1,2,3,4,5,6,7,8,9,10],2) my code returns as expected.
P.S: I am specifically looking to find what's wrong with this code instead of a different code/approach altogether.

Basically you need just one loop, because you splice the array and take a chunk of the wanted size of it.
This behaviour could be used to loop until the array has a length of zero and exit the loop.
In this case the result is ready.
function chunkArrayInGroups(arr, size) {
var newArr = [];
// for (var i = 0; i < arr.length; i++) {
while (arr.length) { // add this for looping and checking
// for (var j = 0; j < size; j++) {
newArr.push(arr.splice(0, size)); // keep this for doing the work!
// }
}
// var result = [];
// for (i = 0; i < newArr.length; i++) {
// if (newArr[i].length != 0) {
// result.push(newArr[i]);
// }
// }
// return result;
return newArr; // return only newArray
}
console.log(chunkArrayInGroups([0, 1, 2, 3, 4, 5, 6, 7, 8], 2));
.as-console-wrapper { max-height: 100% !important; top: 0; }

You can just do the following:
var size = 2;
var arr = [0,1,2,3,4,5,6,7,8];
var newArray = [];
for(var i = 0; i < arr.length; i+=size){
newArray.push(arr.slice(i,i+size))
}
console.log(newArray); //will output [[0,1],[2,3],[4,5],[6,7],[8]]

Your problem is that you are not treating the case where the remaining in the array is less than the given size, in other words the case when arr.length < size, so the remaining items in the array won't be taken into account in the chunk array.
You need to test upon it, I updated your code so it works perfectly:
function chunkArrayInGroups(arr, size) {
// Break it up.
var newArr =[];
while(size<arr.length){
newArr.push(arr.splice(0, size ));
}
if(arr.length<size){
newArr.push(arr);
}
}
Demo:
function chunkArrayInGroups(arr, size) {
// Break it up.
var newArr =[];
while(size<arr.length){
newArr.push(arr.splice(0, size));
}
if(arr.length<size){
newArr.push(arr);
}
return newArr;
}
console.log(chunkArrayInGroups([0, 1, 2, 3, 4, 5, 6, 7,8], 2));
Note:
There's no need for using the result array as it's just a copy of the newArr, you could just return newArr without copying it.

Related

Algorithm problem with array subsequences [duplicate]

I am trying to write a function that will take an array and n as parameters,
it will return all subsets of that array with n elements, have tried a couple things, couldn't yet succeed.
thanks to whoever put it here, this functions is way too complicated and doesn't do the job, basically what I tried to do here is to pick out one element from a 4 element array to create its 3 element subsets. It doesn't even take N as parameter. it returns all 3 element subsets but also identical ones, so I have to filter them out as well, in any case I will keep trying.
function findSubsets(array) {
var answers = [];
var firstArray = array;
for (i = 0; i < array.length; i++) {
array = firstArray;
for (var k = 0; k < array.length; k++) {
if (k != i) {
var subset = array.splice(k, 1);
answers.push(array); array.splice(k, 0, subset[0]);
}
}
}
}
That not as complicated as it seems. This one is optimized because it doesn't creates useless temporary arrays during the process.
function findSubsets(array, n) {
var answers = [];
for(var i = 0 ; i < array.length ; i += n) {
answers.push(array.slice(i, i + n));
}
return answers;
}
findSubsets([1, 2, 3, 4, 5, 6, 7, 8, 9], 2) // --> [[1, 2], [3, 4], [5, 6], [7, 8], [9]]
findSubsets([1, 2, 3, 4, 5, 6, 7, 8, 9], 3) // --> [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
You can try this solution
var subsetArray = (function() {
return {
getResult: getResult
}
function getResult(array, n) {
function isBigEnough(value) {
return value.length === n;
}
var ps = [
[]
];
for (var i = 0; i < array.length; i++) {
for (var j = 0, len = ps.length; j < len; j++) {
ps.push(ps[j].concat(array[i]));
}
}
return ps.filter(isBigEnough);
}
})();
var arr = [1, 2, 3, 4,5,6,7,8,9];
console.log(subsetArray.getResult(arr,2));

Looping into nested arrays

I am going through an exercise that asks me to remove the arrays that have elements that match with another variable.
e.g.
filteredArray([[10, 8, 3], [14, 6, 23], [3, 18, 6]], 18)
should return [[10, 8, 3], [14, 6, 23]]
Given the fact that we are working with nested arrays I though about using a double for to loop into each element.
Like this:
function filteredArray(arr, elem) {
let newArr = [];
for (let i = 0; i < arr.length; i++) {
for (let j = 0; j < arr[i].length; j++) {
if (arr[i][j] != elem) {
newArr.push(arr[i]);
}
}
// change code above this line
return newArr;
}
}
console.log(filteredArray([[3, 2, 3], [1, 6, 3], [3, 13, 26], [19, 3, 9]], 3));
The expected result was to have an empty array, but it gives me:
[3, 2, 3]
The right solution is as follow:
function filteredArray(arr, elem) {
let newArr = [];
for (let i = 0; i < arr.length; i++) {
if (arr[i].indexOf(elem) == -1) { //Checks every parameter for the element and if is NOT there continues the code
newArr.push(arr[i]); //Inserts the element of the array in the new filtered array
};
};
return newArr;
};
console.log(filteredArray([[3, 2, 3], [1, 6, 3], [3, 13, 26], [19, 3, 9]], 3));
Which makes sense, but I do not understand why mine is wrong.
Your issue is with:
if (arr[i][j] != elem) {
newArr.push(arr[i]);
}
You're pushing your array into newArr each time an inner element (newArr[i][j]) doesn't equal the filter element (elem). Instead, you want to push it into newArr if all the items in arr[i] are not equal to the elem. You could do this a few ways, one way would be to use a variable found which acts as a flag indicating whether the elem was found in any of the inner lists, and then add it if it was not found:
function filteredArray(arr, elem) {
let newArr = [];
for (let i = 0; i < arr.length; i++) {
let found = false;
for (let j = 0; j < arr[i].length; j++) {
if (arr[i][j] == elem) {
found = true;
}
}
if(!found) {
newArr.push(arr[i]);
}
}
// move return out of for loop
return newArr; // change code above this line
}
console.log(filteredArray([[3, 2, 3], [1, 6, 3], [3, 13, 26],
[19, 3, 9]], 3));
You are getting [3, 2, 3] because you are returning from inside the first for loop. So, it only ever checks the first inner array. Even if you move it outside, the entire 2d array will be returned because every inner array has an element which will fail arr[i][j] == elem condition.
Alternatively, you could use filter and includes like this:
function filteredArray(arr, elem) {
return arr.filter(a => !a.includes(elem))
}
console.log(filteredArray([[3, 2, 3], [1, 6, 3], [3, 13, 26], [19, 3, 9]], 3));
You check every element of the subarray, and if that does not match elem you push the subarray to the result. That means for [3, 18, 6] in your first example, it will check 3 against elem (18), then push that array, check 18 against elem, which won't fullfill the condition, then it will check 6 against 18 which does match again, the array gets pushed again. Instead you should check the whole array against the value, then push.
outer: for (let i = 0; i < arr.length; i++) {
for (let j = 0; j < arr[i].length; j++) {
if (arr[i][j] == elem) {
continue outer; // if one matches, exit the inner loop
}
// all checked, push
newArr.push(arr[i]);
}
}
There some wrong things in your code:
You let return in for loop.
You check every element in every sub array and push to result array when having the difference
I edit your code as below:
function filteredArray(arr, elem) {
let newArr = [];
for (let i = 0; i < arr.length; i++) { var check = false;
for (let j = 0; j < arr[i].length; j++) {
if (arr[i][j] == elem) {
check = true;
}
}
} // change code above this line
return newArr;
}

Elements in Array1 that are equal to or less than elements in array2?

Scenario:
If given an Array1, such as [1, 2, 3], and Array2 [2,4], I need the output to be [2, 3] because there are 2 elements in Array1 that are less than or equal to Array2[1] and 3 elements in Array1 that are less than or equal to Array2[2].
So far, I've got this...
function counts(nums, maxes) {
let empArr = [];
//compare SECOND ARRAY maxes
for (let i = 0, count = 0; i < maxes.length; i++) {
//to FIRST ARRAY nums
for (let j = 0; j < nums.length; j++) {
if (nums[j] <= maxes[i]) {
count++;
}
}
empArr.push(count);
}
return empArr
}
console.log(counts([1, 2, 3], [2, 3]));
This gives me [2, 5] yet I expect [2, 3]. Any help here? Thanks!
The count = 0; declaration within your for() doesn't do what you seem to think it does. Declarations of this nature within a for constructor are only run once before the first iteration of the loop. Manually reset your count at the top of the loop:
function counts(nums, maxes) {
let empArr = [];
//compare SECOND ARRAY maxes
for (let i = 0; i < maxes.length; i++) {
let count = 0;
//to FIRST ARRAY nums
for (let j = 0; j < nums.length; j++) {
if (nums[j] <= maxes[i]) {
count++;
}
}
empArr.push(count);
}
return empArr
}
console.log(counts([1, 2, 3], [2, 3]));

Finding unused combinations

What is a fast way to find combinations that aren't present in an array yet?
E.g, I have list of points: [1, 2, 4, 9]
And I have a list of connections [[1,2], [1,4], [1,9], [2,4], [4,9]]
So the missing connection in this list is [2,9]. As there is one requirement: every integer must be connected to a bigger integer.
var points = [1, 2, 4, 9];
var connections = [[1,2], [1,4], [1,9], [2,4], [4,9]];
var missing = [];
for(i = 0; i < points.length; i++){
for(j = i + 1; j < points.length; j++){
var found = false;
for(var a = 0; a < connections.length; a++){
if(connections[a][0] == points[i] && connections[a][1] == points[j]){
found = true;
break;
}
}
if(!found) missing.push([points[i], points[j]]);
}
}
console.log(missing);
The above code works, but the amount of for loops makes me think it is reasonably slow. Is there any faster way to do this? View jsfiddle
By sorting the array, you can do it with 2 nests. Sorting takes O(n log n), and the loops are basically O(n ^ 2).
var points = [1, 2, 4, 9];
var connections = [
[1, 2],
[1, 4],
[1, 9],
[2, 4],
[4, 9]
];
connections.sort();
var missing = [];
var currentIndex = 0;
for (var i = 0; i < points.length; i++) {
for (var j = i + 1; j < points.length; j++) {
if (connections[currentIndex][0] == points[i] && connections[currentIndex][1] == points[j]) {
currentIndex++;
} else {
missing.push([points[i], points[j]]);
}
}
}
console.log(missing);
You can use .reduce method in order to generate all the combination of two elements.Then the only thing that will remain is to get the difference from two arrays.
For this, you can use filter method which accepts a callback method.
var points = [1, 2, 4, 9];
points=points.sort();
var connections = [[1,2], [1,4], [1,9], [2,4], [4,9]];
var combinations = points.reduce(function(arr,elem,i){
for(j=i+1;j<points.length;j++)
arr.push([elem,points[j]]);
return arr;
},[]);
var diff=combinations.filter(function(elem,i){
return connections.find(a=>a[0]==elem[0] && a[1]==elem[1])==undefined;
});
console.log(diff);
You could iterate only the outer loop until length - 2 and use a hash table for inserted connections. The sort order of connections does not matter.
var points = [1, 2, 4, 9],
connections = [[1, 2], [1, 4], [1, 9], [2, 4], [4, 9]],
missing = [],
i, j,
pair,
connected = Object.create(null);
connections.forEach(function (a) {
connected[a.join()] = true;
});
for (i = 0; i < points.length - 1; i++) {
for (j = i + 1; j < points.length; j++) {
pair = [points[i], points[j]];
connected[pair.join()] || missing.push(pair);
}
}
console.log(missing);
.as-console-wrapper { max-height: 100% !important; top: 0; }

Javascript why array.slice() doesn't work when the first value is 0?

I have a problem, I don't understand why arr.slice doesn't work when the first value is 0, the returned array is empty:
function chunkArrayInGroups(arr, size) {
var newArr = [];
for (var i = 0; arr[i]; i += size) {
newArr.push(arr.slice(i, i + size));
}
return newArr;
}
console.log(chunkArrayInGroups([0, 1, 2, 3, 4, 5, 6], 3));
You end direct the loop with the condition, which evaluates as false.
arr[i] -> arr[0] -> 0 -> false -> end for loop
Use the length of the array as check
for (var i = 0; i < arr.length; i += size) {
// ^^^^^^^^^^^^^^
function chunkArrayInGroups(arr, size) {
var newArr = [];
for (var i = 0; i < arr.length; i += size) {
newArr.push(arr.slice(i, i + size));
}
return newArr;
}
console.log(chunkArrayInGroups([0, 1, 2, 3, 4, 5, 6], 3));
try with this
function chunkArrayInGroups(arr, size) {
// Break it up.
var newArr = [];
for (var i = 0; typeof arr[i]!='undefined'; i += size) {
newArr.push(arr.slice(i, i + size));
}
return newArr;
}
chunkArrayInGroups([0, 1, 2, 3, 4, 5, 6], 3)
The problem is arr[i] not arr.slice.
First Element of [0, 1, 2, 3, 4, 5 ,6] is 0 and it is false.
Just use other conditions like i < arr.length in for statement.
for (var i = 0; arr[i]; i += size) , arr[0] is 0, means false, so the loop is never entered

Categories