Turning a multidimensional array into a single array - javascript

I'm doing the following codesignal:
Each of the rooms has a different cost, and some of them are free, but there's a rumour that all the free rooms are haunted! Since the CodeBots are quite superstitious, they refuse to stay in any of the free rooms, or any of the rooms below any of the free rooms.
Given matrix, a rectangular matrix of integers, where each value represents the cost of the room, your task is to return the total sum of all rooms that are suitable for the CodeBots (ie: add up all the values that don't appear below a 0).
Example
For
matrix = [[0, 1, 1, 2],
[0, 5, 0, 0],
[2, 0, 3, 3]]
the output should be
solution(matrix) = 9.
This is what I came up with, but it's not passing.
function solution(matrix) {
let rooms = []
for (let i = 0; i < matrix.length; i++) {
if (matrix[i] !== 0 || matrix[i-4] !== 0) {
rooms.push(i)
}
}
rooms.reduce((a, b) => a + b, 0)
}
I think it's not passing because its three small arrays in one large one. So is there a way to easily combine the three small arrays into one large one, then I can loop over it and run the conditional?

You don't need to convert to 1d array as it will be extra work, instead you solve it as follows:
you need to check whether the item above the one you are currently at is 0 or not. The item above any item in a 2d array is at index [i-1][j] where i is your current item. Make sure at i = 0 you directly add the item to the array to avoid getting index out of bounds exception.
This is my code:
let matrix = [[0, 1, 1, 2],
[0, 5, 0, 0],
[2, 0, 3, 3]];
let sum = 0;
for(i = 0; i < matrix.length; i++) {
for(j = 0; j < matrix[i].length; j++) {
if(i === 0) {
sum += matrix[i][j];
continue;
}
if(i - 1 < 0) continue;
if(matrix[i - 1][j] !== 0) sum += matrix[i][j];
}
}
console.log(sum)

Loop over rows & columns, when 0 is found, sum 0 for that and further values in that column:
const matrix = [
[0, 1, 1, 2],
[0, 5, 0, 0],
[2, 0, 3, 3]
];
function solution (matrix) {
let skip = {}, sum = 0;
for (const a of matrix)
for (let i = 0; i < a.length; i++)
sum += skip[i] || (skip[i] = !a[i]) ? 0 : a[i];
return sum;
};
console.log(solution(matrix));

Related

Remove particular array elements and push them to the back of the array [duplicate]

This question already has answers here:
Move zeroes to end of array in javascript - how to return nothing?
(21 answers)
Closed last year.
Trying to remove all 0's from an array and return them in the same array
So for example if I have this as an array
let arrThree = [9,0,9,1,2,1,1,3,1,9,0,0,9,0,0,0,0,0,0,0]
I would get this:
let arrThree = [9,9,9,1,2,1,1,3,1,9,9,0,0,0,0,0,0,0,0,0,0,0]
This is what I wrote:
var remove = function (arr) {
let test = [];
for(let i = 0; i < arr.length; i++){
arr[i] === 0 ? test.push(arr.splice(i,1)) : false //if i is 0 then we want to push that into another array
}
arr.push(...test)
return [].concat(...arr)
}
When I run this function I get this
[
9, 9, 1, 2, 1, 1, 3,
1, 9, 0, 9, 0, 0, 0,
0, 0, 0, 0, 0, 0
]
Not sure where I am going wrong?
You need only two iterations, one for finding non zero values and another to put zeroes to the right side until end of the array. You need no array pushing or splicing.
const
move0 = array => {
let i = 0,
j = 0;
while (i < array.length) {
if (array[i]) array[j++] = array[i];
i++;
}
while (j < array.length) {
array[j] = '#'; // in reality it is zero
j++;
}
},
array = [9, 0, 9, 1, 2, 1, 1, 3, 1, 9, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0];
move0(array)
console.log(...array);
If you don't need to have any sorting on the non-zero elements, a rather efficient solution would be to swap the left-most 0 with the right-most non-zero element. Once your indices for tracking where you are on the left and right cross you'll know you're done.
function moveZeros(arr) {
let i = 0;
let j = arr.length - 1;
while(i < j) {
// Found a 0 to the left of a non-zero, swap.
if(arr[i] == 0 && arr[j] != 0) {
let tmp = arr[j];
arr[j] = arr[i];
arr[i] = tmp;
}
// Find a zero
if(arr[i] != 0) {
i++;
}
// Find a non-zero
if(arr[j] == 0) {
j--;
}
}
return arr;
}
console.log(moveZeros([1,2,0,3,0,0,0]));
console.log(moveZeros([9,0,9,1,2,1,1,3,1,9,0,0,9,0,0,0,0,0,0,0]));
The issue with your code is you change the length of arr with arr.splice(i,1). This messes up the loop condition i < arr.length.
To fix your code, you can loop backwards through the array. So as the length of the array shortens, i is still valid.
let arrThree = [9,0,9,1,2,1,1,3,1,9,0,0,9,0,0,0,0,0,0,0];
var remove = function(arr) {
let test = [];
for(let i = arr.length - 1; i >= 0; --i) {
if (arr[i] === 0) test.push(arr.splice(i, 1)[0]);
}
return arr.concat(test);
}
console.log(remove(arrThree));
There are a few other ways to do this. One is to use filter to create 2 arrays - one with no 0 and one with all 0 and join them:
let arrThree = [9,0,9,1,2,1,1,3,1,9,0,0,9,0,0,0,0,0,0,0];
let remove = (arr) => arr.filter(i => i != 0).concat(arr.filter(i => i == 0));
console.log(remove(arrThree));

Why does my sort implementation not work?

I'm trying to sort an integer array without using sort function. I know there are other solutions available on Stack Overflow. I want to know what is wrong with my code. It performs ascending sort except for the first number in the array.
let arr = [2,4,5,1,3,7];
let iterable = true;
let iterationCount = 0;
while(iterable) {
for(var i=iterationCount;i<=arr.length;i++) {
if (arr[i] > arr[i+1]) {
let temp=arr[i];
arr[i]=arr[i+1];
arr[i+1]=temp;
}
}
iterationCount++;
if (iterationCount == arr.length) {
iterable = false;
}
}
console.log(arr)
The output is [2, 1, 3, 4, 5, 7] while it should be [1, 2, 3, 4, 5, 7].
You could change the outer loop for keeping the last index for checking and iterate until before the last index, because in the first inner loop, the max value is now at the greatest index and any further iteration do not need to check the latest last item.
let array = [2, 4, 5, 1, 3, 7],
iterationCount = array.length;
while (iterationCount--) {
for (let i = 0; i < iterationCount; i++) {
if (array[i] > array[i + 1]) {
let temp = array[i];
array[i] = array[i + 1];
array[i + 1] = temp;
}
}
}
console.log(array);
Each time it goes around the inner loop, it moves each element zero or one spaces to the left.
Each time it goes around the outer loop, it ignores one more element from the left hand side.
This means that it assumes that after one loop the left most element is the smallest element (and after two loops, the two left most elements are the two smallest).
However, because of (1) the 1 will have moved from position 3 to position 2 but it needs to be in position 0.
Wikipedia has a selection of popular sorting algorithms you should read up on if you are implementing sorting from scratch.
I fixed the for loop to always start at 0, then it works.
let arr = [2, 4, 5, 1, 3, 7];
for (let j = 0; j < arr.length; j++) {
for (let i = 0; i < arr.length; i++) {
if (arr[i] > arr[i + 1]) {
const temp = arr[i];
arr[i] = arr[i + 1];
arr[i + 1] = temp;
}
}
}
console.log(arr)
EDIT: I made the whole thing a little shorter

Multi-dimensional Array; JavaScript; Algorithum

Details
I'm working on an algo dealing with a multi-dimensional array. If there is a zero, then the elements of the same column, but following arrays will also equal zero. I want to be able to sum the items that are not zeroed out.
Example:
matrix = [[0, 1, 1, 2],
[0, 5, 0, 0],
[2, 0, 3, 3]] --->2, 3, and 3 will not be counted since there is a zero above it.
the output should be: 1+1+2+5 = 9
My work so far
function matrixElementsSum(matrix) {
var sum = 0;
for(var i=0;i<matrix.length;i++){
console.log(matrix[i])
for(var j=0;j<=matrix.length;j++){
console.log(matrix[i][j])
if(matrix[i][j] == 0){
console.log(true)
//------------>Here is my problem
}
else {
console.log(false)
}
if(matrix[i][j] !== 0){
sum+=matrix[i][j];
}
}
}
return sum;
}
I wanted to use this:
matrix[i+1][j] = 0;
but I get this error:
TypeError: Cannot read property '1' of undefined
Can someon help me understand why my thought process doesn't work and any suggestion to proceed?
Thank you!
Working with rows in a matrix with Javascript is usually much easier than working with columns. So one clean way of writing this is to first transpose the matrix (flipping it over the northwest-southeast diagonal) and then summing each row until you hit a zero, finally summing those results.
[
[ 0, 0, 5 ], // => 0 = 0
[ 1, 5, 0 ], // => 1 + 5 = 6
[ 1, 0, 3 ], // => 1 = 1
[ 2, 0, 3 ], // => 2 = 2
] // +__
// 9
transpose and sum functions are quite easily (and might well be stored in one's personal utility library, as they are likely to get reused.
We also need a sumToFirstZero function. Here we write a recursive one that manages to bury a little complexity since n ? distinguishes from everything else our two base cases - when we've completed the row and therefore n is undefined, and when n is zero. In either of those cases, we simply return 0. In other cases, we add the current value to a recursive call on the remainder of the array.
The main function just puts these three together.
const transpose = (xs) =>
xs [0] .map ((_, i) => xs .map (r => r[i]))
const sum = (ns) =>
ns .reduce ((a, b) => a + b, 0)
const sumToFirstZero = ([n, ...ns]) =>
n ? n + sumToFirstZero (ns) : 0
const problem = (matrix) =>
sum (transpose (matrix) .map (sumToFirstZero))
console .log (problem ([
[0, 1, 1, 2],
[0, 5, 0, 0],
[2, 0, 3, 3]
]))
To make it clear how sumToFirstZero manages to bury a little complexity, this would be a more logically clear version of the same function:
const sumToFirstZero = ([n, ...ns]) =>
n == undefined
? 0
: n == 0
? 0
: n + sumToFirstZero (ns)
But since n has to be a number or undefined if we bottom out on the recursion, we can take advantage of JS's boolean coercion with (! n) ? 0 : n + sumToFirstZero (ns), or, as we do above with n ? n + sumToFirstZero (ns) : 0
Of course we don't have to do this on the (transposed) rows. We could work directly on the columns, fiddling with array parameters. But I find this much simpler.
If you don't want to modify the matrix during the algorithm, then one solution is to have flags that indicate for each column whether or not you have already encountered a 0 in that column:
function matrixElementsSum(matrix) {
let sum = 0;
let flags = Array(matrix[0].length).fill(true);
for (let row of matrix) {
for (let j = 0; j < flags.length; j++) {
if (flags[j] &&= row[j]) sum += row[j];
}
}
return sum;
}
let matrix = [[0, 1, 1, 2],
[0, 5, 0, 0],
[2, 0, 3, 3]];
console.log(matrixElementsSum(matrix));
Note that your loop on j should have as condition j < matrix[0].length
If your IDE complains about the assignment in the if condition, then you can opt to split the assignment from the condition:
flags[j] &&= row[j];
if (flags[j]) sum += row[j];
Or, if you have no support for this operator:
flags[j] = flags[j] && row[j];
if (flags[j]) sum += row[j];
Try this code
const mat1 = [[0, 1, 1, 2], [0, 5, 0, 0], [2, 0, 3, 3]]
function matrixElementsSum(matrix) {
for (let i = 0; i < matrix.length; i++) {
const row = matrix[i]
for (let j = 0; j < row.length; j++) {
if (matrix[i][j] === 0) {
for (let k = i; k < matrix.length; k++) {
matrix[k][j] = 0
}
}
}
}
let total = 0
for (let i of matrix)
for (let j of i)
total += j;
return total;
}
console.log(matrixElementsSum(mat1));

BFS that returns shortest path on a 2nd array /unwighted graph

I know this has been asked before but I can't seem to figure out the solution from the examples and translate them to javascript. not even when following :
https://en.wikipedia.org/wiki/Dijkstra%27s_algorithm
I have an unweighted graph or 2d array for example that looks like this:
const testMatrix = [
[0, 0, 0, 0],
[0, 0, 0, 0],
[0, 1, 0, 0],
[0, 1, 0, 0]
];
I then Traverse that using BFS: (i currently hardCoded the item to find as element 2,2 in the array).
And return the seen list item list. but I can't figure out how the seen list supposes to show the way to the shortest path.
const traversalBFS = function(matrix) {
counter = 0;
const seen =
new Array(matrix.length).fill(0).map(() => new Array(matrix[0].length).fill(false));
const values = [];
const queue = [[0, 0]];
while(queue.length) {
const currentPos = queue.shift();
const row = currentPos[0];
const col = currentPos[1];
if(row < 0 || row >= matrix.length || col < 0 || col >= matrix[0].length || seen[row][col] || matrix[row][col] === 1) {
continue;
}
counter++;
seen[row][col] = true;
values.push(matrix[row][col]);
if(row === 2 && col === 2) {
return seen;
}
for(let i = 0; i < directions.length; i++) {
const currentDir = directions[i];
queue.push([row + currentDir[0], col + currentDir[1]]);
}
}
return false;
}
even if I run this code
temp = traversalBFS(testMatrix);
let path = [];
for(i = 0; i <= 2; i++) {
for(j = 0; j <= 2; j++) {
if(temp[i][j]) {
path.push([i, j]);
}
}
}
it will return:
0: (2) [0, 0]
1: (2) [0, 1]
2: (2) [0, 2]
3: (2) [1, 0]
4: (2) [1, 1]
5: (2) [1, 2]
6: (2) [2, 0]
7: (2) [2, 2]
which is not a correct path in any way, and also not the shortest path.
expected result example:
hmmm lets say end point will be 1,1 and start will be 0, 0
the expected result is an array with the shortest path:
[[0,0], [0, 1], [1,1]]
if the start point is 0, 0 and the end point is 2,2:
I think the result should be:
[[0,0], [0, 1], [1,1],[1,2],[2,2];
using the test matrix I wrote as an example. as there are no 1 aka walls in the way.
For getting an ide how Dijkstra's algorithm work, you could take the approach of the given link and take a large value for a start and take smaller values as soon as the neighbours have them.
This example uses (step) values instead of indices, but it could be replaced by the coordinates of the path to the target.
This approach uses obstacle avoidance and a short cicuit if the target is found.
const
travel = (array, from, to) => {
const
go = (i, j, smallest) => {
if (array[i]?.[j] === 1) return;
if (i === to[0] && j === to[1]) return;
if (unvisited[i]?.[j] > smallest) {
unvisited[i][j] = smallest;
go(i + 1, j, smallest + 1);
go(i - 1, j, smallest + 1);
go(i, j + 1, smallest + 1);
go(i, j - 1, smallest + 1);
}
},
unvisited = testMatrix.map(a => a.map(_ => Number.MAX_VALUE));
go(from[0], from[1], 0);
return unvisited;
},
testMatrix = [[0, 0, 0, 0], [0, 0, 0, 0], [0, 1, 0, 0], [0, 1, 0, 0]],
result = travel(testMatrix, [0, 0], [3, 2]);
result.forEach(a => console.log(a.map(v => v === Number.MAX_VALUE ?'*': v).join(' ')));

Sum in 2-dimensional array

I have a matrix :
matrix = [[0, 1, 1, 2],
[0, 5, 0, 0],
[2, 0, 3, 3]]
I need to calculate Sum of all array elements which are not under 0
So, in this example Sum should be = 9
I have this function:
function matrixElementsSum(matrix) {
// Write your code here
var Summa =0
for (i = 0; i<4; i++){
var sum =0;
// console.log(matrix[i].length); //4
for(j=0; j<matrix.length; j++){
console.log("Matrix JI "+ matrix[j][i])
sum = sum +matrix[j][i];
if (matrix[j][i-1]!=0){
console.log(matrix[j][i-1])
Summa =Summa+ sum;
}
}
console.log('-----------' +Summa)
console.log("Sum "+sum);
}
return Summa;
}
i think i need to change if (matrix[j-1][i]!=0) but it doesn't work
You can use reduce() and inside forEach() loop for this. If the current element in foreach loop is zero then you can store index of that element in one other object zero and you can use that object to check if there was zero with same index.
var matrix = [
[0, 1, 1, 2],
[0, 5, 0, 0],
[2, 0, 3, 3]
]
var zero = {}
var sum = matrix.reduce(function(r, e, i) {
e.forEach(function(n, j) {
if (n == 0) zero[j] = true;
if (!zero[j]) r += n;
})
return r;
}, 0)
console.log(sum)
You can sum 2 arrays and ignore numbers from the bottom array, which items from the same index on the top array are 0.
Now you can iterate the matrix from the end, and sum the resulting array.
const matrix = [[0, 1, 1, 2], [0, 5, 0, 0], [2, 0, 3, 3]];
const sumNotUnderZero = (bottom, top) =>
top.map((v, i) => v ? v + bottom[i] : v);
const result = matrix.reduceRight(sumNotUnderZero)
.reduce((s, n) => s + n);
console.log(result);
You could use Array#reduceRight for building another array with valued column sums and then use Array#reduce for a single number.
var matrix = [[0, 1, 1, 2], [0, 5, 0, 0], [2, 0, 3, 3]],
result = matrix.reduceRight(function (a, b) {
return b.map(function (c, i) {
return c && c + a[i];
});
}).reduce(function (a, b) {
return a + b;
});
console.log(result);
Should be able to simplify it and use this:
function matrixElementsSum(matrix) {
var Summa =0
for (i = 0; i < matrix.length; i++)
for(j = 0; j < matrix[i].length; j++)
if (matrix[i-1][j] != 0)
Summa = Summa + matrix[i][j];
return Summa;
}
You need to access first the array above your current one, hence the matrix[i-1] and then the same column, hence the [j] in (matrix[i-1])[j] ~ matrix[i-1][j]

Categories

Resources