how to spirally traverse a matrix recursively - javascript - javascript

Please look at this JSFiddle: https://jsfiddle.net/hc2jcx26/
I am trying to spirally traverse a matrix output (any size) so that it prints each element in spiral order to console.log every 2 seconds:
var output = [[0, 1, 2, 3],
[4, 5, 6, 7]];
I am expecting this output:
0
1 //after 2 seconds delay
2 //after 2 seconds delay
3 //etc.
7
6
5
4
But I am not getting this with the code above. The output is all over the place and doesn't even have the right number of elements. I am using recursion to add a delay in my loop after every iteration (through setTimeout), but I do not think I am setting the variables correctly. But when I look at the code, it makes sense to me. What am I missing here?

This is my approach to your problem.
Iterative version
var matrix1 = [
[1, 2, 3, 4],
[5, 6, 7, 8],
[9, 10, 11, 12],
[13, 14, 15, 16]
], matrix2 = [
[1, 2, 3],
[4, 5, 6],
[7, 8, 9],
[10, 11, 12]
], matrix3 = [
[0, 1, 2, 3],
[4, 5, 6, 7]
], matrix4 = [
[1, 2, 3],
[4, 5, 6],
[7, 8, 9]
];
(function (matrix) {
var i,
nRows = matrix.length,
nCols = matrix[0].length,
rowLimit = nRows - 1,
colLimit = nCols - 1,
rounds = 0,
printedElements = 0,
nElements = nRows * nCols,
timeoutLapse = 2000;
function print(val) {
printedElements += 1;
setTimeout(function () {
console.log(val);
}, printedElements * timeoutLapse);
}
do {
for (i = rounds; i <= colLimit - rounds; i += 1) {// from left to right
print(matrix[rounds][i]);
}
for (i = rounds + 1; i <= rowLimit - rounds; i += 1) {// from top to bottom
print(matrix[i][colLimit - rounds]);
}
for (i = colLimit - rounds - 1; i >= rounds; i -= 1) {// from right to left
print(matrix[rowLimit - rounds][i]);
}
for (i = rowLimit - rounds - 1; i >= rounds + 1; i -= 1) {// from bottom to top
print(matrix[i][rounds]);
}
rounds += 1;
} while (printedElements < nElements);
})(matrix4);
Here's the fiddle (you'll have to open the console in order to see the results).
Recursive version
var matrix1 = [
[1, 2, 3, 4],
[5, 6, 7, 8],
[9, 10, 11, 12],
[13, 14, 15, 16]
], matrix2 = [
[1, 2, 3],
[4, 5, 6],
[7, 8, 9],
[10, 11, 12]
], matrix3 = [
[0, 1, 2, 3],
[4, 5, 6, 7]
], matrix4 = [
[1, 2, 3],
[4, 5, 6],
[7, 8, 9]
];
(function(matrix){
var printedElements = 0,
timeoutLapse = 1000;
function print(val) {
printedElements += 1;
setTimeout(function () {
console.log(val);
}, printedElements * timeoutLapse);
}
function printArray(arr) {
for(var i = 0; i < arr.length; i++) {
print(arr[i]);
}
}
// Recursive algorithm, consumes the matrix.
function printMatrix(matrix, direction) {
var dir = direction % 4,
rowLimit = matrix.length - 1,
i;
if (dir === 0) {// from left to right
printArray(matrix.shift());
} else if (dir === 1) {// from top to bottom
for(i = 0; i <= rowLimit; i++) {
print(matrix[i].pop());
}
} else if (dir === 2) {// from right to left
printArray(matrix.pop().reverse());
} else {// from bottom to top
for(i = rowLimit; i >= 0; i--) {
print(matrix[i].shift());
}
}
if (matrix.length) {// Guard
printMatrix(matrix, direction + 1);
}
}
// Initial call.
printMatrix(matrix, 0);
})(matrix4);
I added some examples in order to test it. I just print out elements of the matrix every two seconds following the spiral pattern.
As you can see, the recursive version is more declarative though it empties the matrix completely. Here's the fiddle

try
var output = [[0, 1, 2, 3],
[4, 5, 6, 7]];
var columns = output[0].length;
var row;
function spiralOrderRecursive (matrix, rowIndex) {
rowIndex = rowIndex || 0;
if (matrix.length) {
row = rowIndex % 2 ? matrix[0].reverse() : matrix[0];
row.forEach(function (item, index) {
setTimeout(function () {
console.log(item);
}, (rowIndex * columns + index) * 2000);
});
spiralOrderRecursive (matrix.slice(1), ++rowIndex);
}
}
spiralOrderRecursive(output);
also NON RECURSIVE
var output = [[0, 1, 2, 3, 5],
[6, 7, 8, 9, 10],
[11, 12, 13, 14, 15],
[16, 17, 18, 19, 20]];;
var columns = output[0].length;
function spiralOrder(output) {
output.forEach(function (row, rowIndex) {
row = rowIndex % 2 ? row.reverse() : row;
row.forEach(function (item, index) {
setTimeout(function () {
console.log(item);
}, (rowIndex * columns + index) * 2000);
});
});
}
spiralOrder(output);

Pseudo-code for what you want to do
spiral_print(matrix)
{
If the matrix has one row
print the row and go to new line
else if the matrix has two rows
print the first row and go to new line
sleep(2)
print the second row in reverse order and go to new line
else
print the first row and go to new line
sleep(2)
print the second row in reverse order and go to new line
sleep(2)
spiral_print(matrix.slice(2))
}

Using JS
UPDATE: Leveraging #acontell's print function
function spiral(matrix) {
if (matrix.length <= 0) {
return
}
for (var i = 0; i < matrix[0].length; i++) {
print(matrix[0][i])
}
//Get last col
for (var i = 1; i < matrix.length; i++) {
print(matrix[i][matrix[0].length - 1])
}
//Get last row
for (var i = matrix[0].length - 2; i >= 0; i--) {
print(matrix[matrix.length-1][i])
}
//Get first column
for (var i = matrix.length - 2; i > 0; i--) {
print(matrix[i][0])
}
matrix = matrix.slice(1, -1)
for (var i = 0; i < matrix.length; i++) {
matrix[i] = matrix[i].slice(1, -1)
}
spiral(matrix)
}
function print(val) {
printedElements += 1;
setTimeout(function () {
console.log(val);
}, printedElements * 2000);
}
var printedElements = 0
matrix = [[1, 2, 3, 4],
[5, 6, 7, 8],
[9, 10, 11, 12],
[13, 14, 15, 16]]
matrix1 = [[1, 2, 3, 4, 31],
[5, 6, 7, 8, 32],
[9, 10, 11, 12, 33],
[13, 14, 15, 16, 34],
[35, 36, 37, 38, 39]]
spiral(matrix1)
Using Python
Note: It's much easier with numpy
def spiral(matrix):
if len(matrix) <= 0:
return
for v in matrix[0]:
print(v)
last_col = [matrix[i][len(matrix[0]) - 1] for i in range(1,len(matrix))]
for v in last_col:
print(v)
last_row = reversed(matrix[len(matrix)-1][0:-1])
for v in last_row:
print(v)
first_col = [matrix[i][0] for i in range (1, len(matrix) - 1)]
first_col = reversed(first_col)
for v in first_col:
print(v)
matrix = matrix[1:len(matrix) - 1]
matrix = [m[1:len(matrix[0]) - 1] for m in matrix]
spiral(matrix)
matrix = [[1, 2, 3, 4],
[5, 6, 7, 8],
[9, 10, 11, 12],
[13, 14, 15, 16]]
matrix1 = [[1, 2, 3, 4, 31],
[5, 6, 7, 8, 32],
[9, 10, 11, 12, 33],
[13, 14, 15, 16, 34],
[35, 36, 37, 38, 39]]
spiral(matrix1)
UPDATE: With numpy
import numpy as np
def spiral(matrix):
if len(matrix) <= 0:
return
for v in matrix[0]:
print(v)
last_col = matrix[1:, -1]
for v in last_col:
print(v)
last_row = reversed(matrix[-1, :-1])
for v in last_row:
print(v)
first_col = reversed(matrix[1:-1, 0])
for v in first_col:
print(v)
matrix = matrix[1:-1, 1:-1]
spiral(matrix)
matrix = [[1, 2, 3, 4],
[5, 6, 7, 8],
[9, 10, 11, 12],
[13, 14, 15, 16]]
matrix1 = [[1, 2, 3, 4, 31],
[5, 6, 7, 8, 32],
[9, 10, 11, 12, 33],
[13, 14, 15, 16, 34],
[35, 36, 37, 38, 39]]
matrix2 = np.array([[1, 2, 3, 4, 31],
[5, 6, 7, 8, 32],
[9, 10, 11, 12, 33],
[13, 14, 15, 16, 34],
[35, 36, 37, 38, 39]])
spiral(matrix2)

Related

What is the difference between these two chunks of code?

Can someone please help me understand the differences between these two programs? I was doing this RallyCoding Prep problem and wrote the first program (and it failed). Then I checked what others did to try and understand but it seems to me that the two programs do basically the same thing, written differently. Can someone help me understand why mine fails and the second program works?
Link to problem: https://www.rallycoding.com/problems/205
--My code--
let k = 16;
let length = Math.sqrt(k);
let height = length;
let arr = []
for(let i = 0; i < length; i++){
let row = [];
for(let x = 1; x <= k; x++){
row.push(x);
}
arr.push(row);
}
console.log(arr)
--Their code--
let k = 16
let c = 1;
const r = Math.sqrt(k);
const result = [];
while(c <= k) {
const block = [];
for (let i = 1; i <= r; i++) {
block.push(c);
c++;
}
result.push(block);
}
console.log(result)
I'm certain I'm missing something very obvious. I hope someone can help me understand this. Thank you!
Since the value of k = 16, the inner loop runs 16 times. So, the result produced by your code is
[
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16],
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16],
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16],
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]
]
And the result produced by their code is
[
[1, 2, 3, 4],
[5, 6, 7, 8],
[9, 10, 11, 12],
[13, 14, 15, 16]
]
So, you can make these changes in your code to get the desired result.
let k = 16;
let length = Math.sqrt(k);
let height = length;
let arr = []
for(let i = 0; i < length; i++){
let row = [];
for(let x = 1; x <= length; x++){
row.push(x + i * length);
}
arr.push(row);
}
You code produces data like this: [[1, 2, 3], [1, 2, 3], ...]
(Each sub-array starts with 1)
You need to produce: [[1, 2, 3], [4, 5, 6], ...]
(Each sub array continues the sequence of the previous one)
the nested forloop you created loop over 16 times
for(let x = 1; x <= k; x++){ row.push(x); }
because K=16 so it will provide an array with 16 element.
the forloop keep runing intel it finish the job.but in the correction they use a "while" loop because The 'while' loop used only when the number of iteration are not exactly known.the are some diff between the two.
Here's a link you can find more

How to summize every second number in an Array?

I'm having trouble summize every second/other number in an Array in Javascript. Any suggestions? (Using Norwegian functions, sorry for that!)
Such as: 2, 4, 6, 8, 10 = 30..
My function for the second/other number is
function tall(nummer) {
var tall = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15];
if (nummer == 5) {
partall = tall.filter((_,i) => i&1);
document.getElementById("tall").innerHTML = partall;
}
and for the final sum:
if (nummer == 9) {
partall = tall.filter((_,i) => i&1);
partall += tall;
document.getElementById("tall").innerHTML = partall;
}
Try the following:
var tall = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15];
let sum = 0;
for (let i = 0; i < tall.length; i += 2){
sum += tall[i];
}
console.log(sum)
Instead of loop over all the number you increment i by 2 thus only looping over the odd numbers.
The simplest way I can see is to use reduce (good for summing) and just don't add in the values for the indexes you don't want to contribute to the sum:
const tall = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15];
const sum = tall.reduce((sum, val, i) => sum + (i & 1 ? val : 0), 0);
console.log(sum);
or
const tall = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15];
const sum = tall.reduce((sum, val, i) => (i & 1 ? sum + val : sum), 0);
console.log(sum);
Array.prototype.reduce is certainly the way to go here:
var sum = [0,1,2,3,4,5,6,7,8,9,10].reduce((sum, n, i) => {
if (i % 2 === 0)
sum += n;
return sum;
}, 0);
console.log(sum);

Split javascript array of numbers into ranges

I have an array such as:
[16, 20, 1, 4, 6, 8, 9, 22, 18, 14, 13, 12]
That I would like split into 6 different arrays based on ranges 1-4, 5-8, 9-12, 13-16, 17-20, 21-24.
What is the simplest way to do this with javascript?
You could use an interval for assigning the numbers to a specific slot.
var array = [16, 20, 1, 4, 6, 8, 9, 22, 18, 14, 13, 12],
interval = 4,
result = array.reduce(function (r, a) {
var slot = Math.floor((a - 1) / interval);
(r[slot] = r[slot] || []).push(a);
return r;
}, []);
console.log(result);
The solution using Array.prototype.filter() function:
var list = [16, 20, 1, 4, 6, 8, 9, 22, 18, 14, 13, 12], i
result = [];
// considering ranges `1-4, 5-8, 9-12, 13-16, 17-20, 21-24`
for (i = 1; i < 24; i+= 4) {
result.push(list.filter(function(d){
return ((i+4 > d) && d >= i); // check if the number between lower and upper bound
}));
}
console.log(result);
Simplest answer:
var numbers = [16, 20, 1, 4, 6, 8, 9, 22, 18, 14, 13, 12];
var array1 = []; // range 1-4
var array2 = []; // range 5-8
for(var i=0; i< numbers.length; i++) {
if(numbers[i]>= 1 && numbers[i] <= 4) {
array1[i] = numbers[i]
} else if(numbers[i]>= 5 && numbers[i] <= 8) {
array2[i] = numbers[i]
}
//... continue for remaining ranges
}

Numbering every number

i want to put number every number using jquery or javascript:
If i input this number:
1, 1, 1, 2, 3, 4, 5, 5, 5, 6, 7, 8, 8, 9, 10 and so on
then my expected output is:
1.1, 1.2, 1.3, 2.1, 3.1, 4.1, 5.1, 5.2, 5.3, 6.1, 7.1, 8.1, 8.2, 9.3, 10.1 and so on
var arr = [1, 1, 1, 2, 3, 4, 5, 5, 5, 6, 7, 8, 8, 9, 10];
var newArr = [arr[0] + ".1"];
var n = 1;
for (var i = 1; i < arr.length; i++) {
if (arr[i] == arr[i - 1]) {
n++;
}
else {
n = 1;
}
newArr.push(arr[i] + "." + n);
}
console.info(newArr);
This does want you want:
var arr = [1, 1, 1, 2, 3, 4, 5, 5, 5, 6, 7, 8, 8, 9, 10];
var newarr = []; check = 0; count = 0;
for(i=0; i<arr.length; i++){
if(check != arr[i]){ count = 1; check = arr[i]; } else { count++; }
newarr.push(check+'.'+count);
}
console.log(newarr);
Ofcourse the numbers should be grouped together, else you will get 1.1,1.2,2.1,3.1,1.1,1.2,5.1 Then you should first do arr.sort()

Generating an matrix from a set of arrays

var set1 = [14, 9, 1, 6, 16],
set2 = [4, 15, 16, 14, 11],
set3 = [16, 10, 2, 3, 8],
set4 = [3, 17, 16, 6, 14],
set5 = [19, 18, 14, 6, 20],
set6 = [6, 15, 8, 7, 2],
set7 = [15, 14, 2, 19, 3],
set8 = [8, 2, 14, 10, 5],
set9 = [11, 6, 8, 10, 18],
set10 = [14, 10, 12, 4, 18],
input = [set1, set2, set3, set4, set5, set6, set7, set8, set9, set10];
// Sort function
function sortFunction(a) {
var len = a.length,
temp, i, j;
for (i = 0; i < len; i++) {
for (j = i + 1; j < len; j++) {
if (a[j] < a[i]) {
temp = a[i];
a[i] = a[j];
a[j] = temp;
}
}
}
return a;
}
// Sorting each sets and finding range of each sets
for (var i = 0; i < len; i++) {
input[i] = sortFunction(input[i]);
minRange.push(Math.min.apply(null, input[i]));
maxRange.push(Math.max.apply(null, input[i]));
}
// Finding the range of input
var minimum = Math.min.apply(null, minRange);
var maximum = Math.max.apply(null, maxRange);
var range = maximum - minimum + 1;
// Matrix table function
var tableArray = [];
function table() {
for (var i = 0; i < len; i++) {
for (var j = 0; j < range; j++) {
if (input[i][j] == j) {
tableArray[i].push(input[i][j]);
} else {
tableArray[i].push(0);
}
}
tableArray.push(tableArray[i]);
}
return tableArray;
}
I am having problem solving this problem: the input is a set of 10 arrays where each array contains 5 different number in range of 1 - 20.
input =[ [14, 9, 1, 6, 16], [4, 15, 16, 14, 11], [16, 10, 2, 3, 8], [3, 17, 16, 6, 14], [19, 18, 14, 6, 20], [6, 15, 8, 7, 2], [15, 14, 2, 19, 3], [8, 2, 14, 10, 5], [11, 6, 8, 10, 18], [14, 10, 12, 4, 18] ]
I would like to generate a 10x20 matrix as output where each row has has 20 numbers with the following pattern:
output = [ [ 1, 0, 0, 0, 0, 6, 0, 0, 9, 0, 0, 0, 0, 14, 0, 16, 0, 0, 0, 0], [ 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 11, 0, 0, 14, 15, 16, 0, 0, 0, 0], [... ], ... ]
Im using JavaScript to solve this...
Create a new output array:
var out = [];
Loop over the input array. For each nested array create a new array in the output array padded with 20 zeros, and then just replace those elements in the output array with the value of the element in the nest input array in the right position. Since you know the size of the nested array, and it's small, its easier just to list each element rather than use an inner loop.
for (var i = 0, l = arr.length; i < l; i++) {
var el = arr[i];
out[i] = Uint8Array(20);
out[i][el[0] - 1] = el[0];
out[i][el[1] - 1] = el[1];
out[i][el[2] - 1] = el[2];
out[i][el[3] - 1] = el[3];
out[i][el[4] - 1] = el[4];
}
DEMO
If your browser doesn't support Uint8Array you can use a separate function to create a padded array:
function padArray() {
var out = [];
for (var i = 0, l = 20; i < l; i++) {
out.push(0);
}
return out;
}
And use:
out[i] = padArray();
You really should have tried it yourself. It's rather easy. Start with an array of 20 zeros, then fill the slots with the values from the array:
function posArray(arr, max) {
var res = [];
for (var i = 0; i < max; i++) res.push(0);
for (var i = 0; i < arr.length; i++) {
var a = arr[i];
if (a > 0 && a <= max) res[a - 1] = a;
}
return res;
}
var output = [];
for (var i = 0; i < input.length; i++) {
output.push(posArray(input[i], 20));
}
Something like this would also work (not tested):
var set1 = [14, 9, 1, 6, 16],
set2 = [4, 15, 16, 14, 11],
set3 = [16, 10, 2, 3, 8],
set4 = [3, 17, 16, 6, 14],
set5 = [19, 18, 14, 6, 20],
set6 = [6, 15, 8, 7, 2],
set7 = [15, 14, 2, 19, 3],
set8 = [8, 2, 14, 10, 5],
set9 = [11, 6, 8, 10, 18],
set10 = [14, 10, 12, 4, 18],
input = [set1, set2, set3, set4, set5, set6, set7, set8, set9, set10];
var output = [];
for (var e=0; e<input.length; e++) {
newRow = [];
for (var i=0;i<20; i++) {
if (input[e].indexOf(i) > -1) {
newRow.push(i);
}
else {
newRow.push(0);
}
}
output.push(newRow);
}
alert(output);

Categories

Resources