[just joined. first post \o/]
I'm working on a 'battleblocks' project idea of mine to help learn JS, where I have a 10x10 css grid of dynamically created divs. They are identifiable from numbers 1 to 100, reading left to right (row 1 has 1,2,3..10, row 2 has 11,12..20 etc). I need to be able to have a nested array of columns that house 10x arrays (columnArray[0] contains 1,11,21..91 - columnArray[1] contains 2,12,22..92 etc). And the same for rows - a row array that has 10x row arrays (rowArray[0] contains 1,2,3..10 - rowArray[1] contains 11,12,13..20 etc).
Ive declared column array globally, but as it stands whatever ive done so far causes a 'aw, snap! something went wrong while displaying this webpage.' error.
loadColsArray();
// load column arrays
function loadColsArray() {
let rowsAr = [];
let count = 0;
for (let c = 1; c <= 10; c++) {
for (let r = 0; r <= 100; r + 10) {
rowsAr[count] = c + r;
count++;
}
columnArray[c - 1] = rowsAr;
count = 0;
rowsAr = [];
}
console.log(columnArray);
}
Any help appreciated.
ps: added code as a snippet, because 'code sample' option broke up my pasted code.
There are a few problems in your code:
The "Aw Snap" is caused by an infinite loop in your code which occurs because you never increment r. You must use r += 10 to increment it by 10.
Since you initialise r to 0, your exit condition must be r < 100, otherwise 11 iterations will occur.
You also need to define columnArray before you use it (it's not defined in the snippet).
Try this:
let columnArray = []; // ←
loadColsArray();
// load column arrays
function loadColsArray() {
let rowsAr = [];
let count = 0;
for (let c = 1; c <= 10; c++) {
for (let r = 0; r < 100; r += 10) { // ←
rowsAr[count] = c + r;
count++;
}
columnArray[c - 1] = rowsAr;
count = 0;
rowsAr = [];
}
console.log(columnArray);
}
Related
I know there are similar questions out there (the closest one I found was this JavaScript; n-dimensional array creation) but most one them are in Python and even this one I found I tried to implement in my code and It didn't work.
So I want to create a function createGrid(L,n) that take as parameters two arrays of same size, L and n. In these, L[i] would specify the size of the grid in dimension i and n[i] would specify the number of points in the same dimension (such as the spacing between points is L[i]/(n[i] - 1). For example, for two dimensions lets say I call "let grid = createGrid([10,10],[2,2])" then the function should return an n+1 dimension array like this:
[[[0,0],[0,10]], [[10,0], [10,10]].
So If I want to access a point in the grid I could simply type, for example, grid[1][0], which will return the point [10,0].
In this moment I am hardcoding this for 3 dimensions like this:
let create3DSquareGrid = function(L, n){
//L should be an array [Lx, Ly, Lz], if not they are all the same
if(!Array.isArray(L)){
L = [L,L,L];
}
//n should be an array [nx, ny, nz], if not they are all the same
if(!Array.isArray(n)){
n = [n,n,n];
}
//calculate the dl of each dimension
var dl = L.map((val,i)=> Math.round(val/(n[i]-1)));
//create the grid
let grid = []
for(let i=0; i<n[0]; i++){
let x = i*dl[0];
let gridJ = [];
for(let j=0; j<n[1]; j++){
let y = j*dl[1];
let gridK = [];
for(let k=0; k<n[2]; k++){
let z = k*dl[2];
gridK.push([x,y,z]);
}
gridJ.push(gridK)
}
grid.push(gridJ);
}
return grid;
}
But I want to extend this by any number of dimensions. I tried to recurse as shown at the question I linked in the beginning but it simply did not work, so I tweaked it a little bit and things got worse, I from that point I just started getting more and more confused.
If you can, please help! And thanks a lot!
You can use a loop. It is a great way to solve this problem.
function createGrid(L, n) {
var ans = L
for (i = 1; i < L.length; i++) {
var tmp = []
for (el of ans) {
innerTmp = []
for (j = 0; j < L.length; j++) {
innerTmp.push([el, L[j]])
}
tmp.push(innerTmp)
}
ans = tmp
}
return ans
}
I have done a code where it will generate 7 random numbers from 0 to 49.
HTML
<button id="btn_generate" onClick="getMyLuckyNumbers()">GENERATE NUMBERS</button>
<div id="display"></div>
JS
function getMyLuckyNumbers() {
for (var allNumbers=[],i=0;i<50;++i) allNumbers[i]=i;
function shuffle(array) {
var tmp, current, top = array.length;
if(top) while(--top) {
current = Math.floor(Math.random() * (top + 1));
tmp = array[current];
array[current] = array[top];
array[top] = tmp;
}
return array;
}
allNumbers = shuffle(allNumbers);
var luckyNumbers = "";
var g;
for (g = 0; g < 7; g++) {
luckyNumbers += allNumbers[g] + "<br>";
}
document.getElementById("display").innerHTML = luckyNumbers;
}
I would like to know how I can omit 0?
I attempted two ways, but both failed.
Attempt 1:
Changed the i=0 to i=1.
for (var allNumbers=[],i=1;i<50;++i)
allNumbers[i]=i;
This did omit 0 but when 0 was randomly supposed to appear, it shows as undefined.
Attempt 2:
I tried to do an if statement.
if(allNumbers != 0) {
allNumbers = shuffle(allNumbers);
}
But this still displays 0 if it happens to be randomly generated.
So, how do I omit 0?
The issue with starting i from 1 is that the 0th index will be empty, and so when accessed gives undefined.
So, if you want to avoid the number 0, you can make i start at 1, but you would need to change the way you add numbers to your array. Instead of adding your numbers to your array by placing them at a specific index, you can .push() them to the end of your array each iteration like so:
// \/------ start at i = 1, the 1st number to be added to your array
for (var allNumbers=[],i=1;i<50;++i)
allNumbers.push(i);
This way, you will fill up your array with numbers from 1 to 49 which can them be shuffled.
I'm trying to speed-up matrices multiplications in pure javascript. Multiplications appear to be very slow above a few hundreds of lines, over the minute on a thousand of lines: you'll see the execution time bellow.
How would you solve this? We are working on a split + parallelization solution in Node.js so I'm looking for the best options to optimize it in pure javascript. My solution has to adapt the parallelized flows itself to the number of CPU threads available (that is unknown at design time).
Some data :
const math = require("mathjs");
// a1 is a 1000x1000 float matrix
// b1 is a 1000x400
math.multiply(a1, b1)
// runs in 19.6 seconds on a CPU 4.2Ghz
// a2 is 1600x1200
// b2 is 1200x800
math.multiply(a2, b2)
// runs in 78 seconds
Array lookup optimization
Arrays are associative lookup tables in JavaScipt - they are inefficient by nature. An optimization of this kind of array access
var array = some_2D_Array;
var nRows = array.length;
var nCols = array[0].length;
for( var r = 0; r < nRows; ++r) {
for( var c = 0; c < nCols; ++c) {
// do something with array[r][c];
}
}
is to replace it with
var array = some_2D_Array;
var nRows = array.length;
var nCols = array[0].length;
for( var r = 0; r < nRows; ++r) {
var aRow = array[r]; // lookup the row once
for( var c = 0; c < nCols; ++c) {
// do something with aRow[c];
}
}
which avoids searching the array object for the row array within each iteration of the inner loop. Performance gain will depend on the JS engine and the number of inner iterations.
Typed Array Usage
Another alternative could be to use a one dimensional typed array to avoid associative array index lookup instead of computing it. Here's some test code I ran in Node so see what difference it might make:
function Mat (rows, cols) {
var length = rows*cols,
buffer = new Float64Array( length)
;
function getRow( r) {
var start = r*cols,
inc = 1;
return { length: cols, start, inc, buffer};
}
function getCol( c) {
var start = c,
inc = cols;
return { length: rows, start, inc, buffer};
}
function setRC(r,c, to) {
buffer[ r*cols + c] = to;
}
this.rows = rows;
this.cols = cols;
this.buffer = buffer;
this.getRow = getRow;
this.getCol = getCol;
this.setRC = setRC;
}
Mat.dotProduct = function( vecA, vecB) {
var acc=0,
length = vecA.length,
a = vecA.start, aInc = vecA.inc, aBuf = vecA.buffer,
b = vecB.start, bInc = vecB.inc, bBuf = vecB.buffer
;
if( length != vecB.length) {
throw "dot product vectors of different length";
}
while( length--) {
acc += aBuf[ a] * bBuf[ b];
a += aInc;
b += bInc;
}
return acc;
}
Mat.mul = function( A, B, C) {
if( A.cols != B.rows) {
throw "A cols != B.rows";
}
if( !C) {
C = new Mat( A.rows, B.cols);
}
for( var r = 0; r < C.rows; ++r) {
var Arow = A.getRow(r);
for (var c = 0; c < C.cols; ++c) {
C.setRC( r, c, this.dotProduct( Arow, B.getCol(c)));
}
}
return C;
}
function test() {
// A.cols == B.rows
let side = 128;
let A = new Mat( side, side)
let B= new Mat( side, side);
A.buffer.fill(1)
B.buffer.fill(1)
console.log( "starting test");
let t0 = Date.now();
Mat.mul( A,B);
let t1 = Date.now();
console.log( "time: " + ((t1-t0)/1000).toFixed(2) +" seconds");
}
test()
Results for multiplying two square matrices (1.1Ghz Celeron):
// 128 x 128 = 0.05 seconds
// 256 x 256 = 0.14 seconds
// 512 x 512 = 7 seconds
// 768 x 768 = 25 seconds
// 1024 x 1024 = 58 seconds
The differences in CPU speed suggest this approach could be significantly faster but ... the code is experimental, the system had no other load and timings were for array multiplication alone - they exclude time taken to decode and populate the array with data. Any serious gain would need to be proven in practice.
I eventually decided that when multiplying two square matrices together, doubling the side dimension used should make the operation take 8 times as long: four times as many result elements to calculate and twice as many elements in vectors used to calculate dot products. The comparative times for 512 x 512 and 1024 x 1024 multiplications fit in line with this expectation.
I have a list of players in denoted as
activeRange[x]
where x will vary from day-to-day.
Each of the x values will have to have AT LEAST 4 more subsequent values (likely a bit more). Ideally I'd like the array to look like:
activeRange[x][y]
So here's what I've done so far:
var MATCH = AllData[TotalRows][TotalColumns+1];
activeRange[TotNumPlayers].push(MATCH);
This is all located within 3 nested for loops.
TotNumPlayers
will iterate through a given set declared at the beginning (somewhat like 23). Once done, the
TotalRows
will iterate, then finally
TotalColumns
I'm running into the following error:
TypeError: Cannot find function push in object mitch
mitch is the value of activeRange[0]. I've been staring at this way too long, so any help would be appreciated!
EDIT: Code inserted below:
PLEASE IGNORE ALL THE COMMENTS. I COPY/PASTED THIS FROM A BIT OF CODE I USED YESTERDAY TO PERFORM A DIFFERENT FUNCTION.
This is the second time I've ever posted on this website, so trying to format this monster to be pretty was scary sounding. Hopefully this is good enough.
This is how activeRange was declared and initialized.
var activeRange = new Array();
for (var b=0; b<=lastRow-2; b++){
activeRange[b] = sheetRANK.getRange(b+2,1).getValue();
}
This is the function.
function getTotalScore(activeRange, w) {
Logger.clear()
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheetWAR = ss.getSheetByName('WAR');
var sheetRANK = ss.getSheetByName('RANK');
var AllData = sheetRANK.getDataRange().getValues();
Logger.log('First');
for (var TotNumPlayers = 0; TotNumPlayers <= activeRange.length; TotNumPlayers++) {
Logger.log('Second');
var f = 0;
for (var TotalColumns = 0; TotalColumns <= AllData[0].length; ++TotalColumns) { // Init n. If n <= the total columns (second dimension), inc n.
Logger.log('Third');
for (var TotalRows = 0; TotalRows <= AllData.length; ++TotalRows) { // Init i. If i <= the total rows (first dimension), inc i.
Logger.log('Fourth');
//try{ // to avoid errors.
if (activeRange[TotNumPlayers] != "") {
Logger.log('Here?');
if (AllData[TotalRows][TotalColumns].valueOf().toUpperCase() == activeRange[TotNumPlayers].toUpperCase()) {
Logger.log('How About Here?');
var MATCH = AllData[TotalRows][TotalColumns + 1];
activeRange.push(TotNumPlayers, MATCH);
for (var Calc = 0; Calc <= activeRange[TotNumPlayers].length - 1; Calc++) {
var OverallScore = ((activeRange[TotNumPlayers][0] * 1.0) + (activeRange[TotNumPlayers][1] * .75) + (activeRange[TotNumPlayers][2] * .50) + (activeRange[TotNumPlayers][3] * .25));
sheetRANK.getRange(activeRange[TotNumPlayers] + 1, 2).setValue(OverallScore);
f = f + 1;
}
if (TotalRows == AllData.length - 1 && TotalColumns == AllData[0].length - 1 && f == 0) {
Browser.msgBox('No names matching \'' + activeRange[TotNumPlayers] + '\' found. Check your spelling!');
return;
}
}
}
}
}
}
}
Try thinking about what kind of data structures you can use to make your life easier. For this particular case, you have a list of players that you want to associate some data with. You'd probably use a structure like:
activeRange = [
{
name: 'mitch',
data: []
}
]
When you want to update the data, you'd simply call activeRange[0].data.push(someData).
activeRange is an array of players and each player is represented by an object with some properties, (name, data, etc).
Calling activeRange[0] yields the first player in your array and activeRange[0].data will yield the data associated with that player, which you can then manipulate however you want (push, pop, etc)
Based on your comments, you need a structure more like this
var activeRange = [
{
name: 'mitch',
otherData: [
10,
11,
12,
13
]
},
{
name: 'viper',
otherData: [
//values
]
}
]
you can access that by activeRange[0].otherData[2]
to add to it, just push into the sub array activeRange[0].otherData.push(newValue)
What I'm basically trying to do is to map an array of data points into a WebGL vertex buffer (Float32Array) in realtime (working on animated parametric surfaces). I've assumed that representing data points with Float32Arrays (either one Float32Array per component: [xx...x, yy...y] or interleave them: xyxy...xy) should be faster than storing them in an array of points: [[x, y], [x, y],.. [x, y]] since that'd actually be a nested hash and all. However, to my surprise, that leads to a slowdown of about 15% in all the major browsers (not counting array creation time). Here's a little test I've set up:
var points = 250000, iters = 100;
function map_2a(x, y) {return Math.sin(x) + y;}
var output = new Float32Array(3 * points);
// generate data
var data = [];
for (var i = 0; i < points; i++)
data[i] = [Math.random(), Math.random()];
// run
console.time('native');
(function() {
for (var iter = 0; iter < iters; iter++)
for (var i = 0, to = 0; i < points; i++, to += 3) {
output[to] = data[i][0];
output[to + 1] = data[i][1];
output[to + 2] = map_2a(data[i][0], data[i][1]);
}
}());
console.timeEnd('native');
// generate data
var data = [new Float32Array(points), new Float32Array(points)];
for (var i = 0; i < points; i++) {
data[0][i] = Math.random();
data[1][i] = Math.random();
}
// run
console.time('typed');
(function() {
for (var iter = 0; iter < iters; iter++)
for (var i = 0, to = 0; i < points; i++, to += 3) {
output[to] = data[0][i];
output[to + 1] = data[1][i];
output[to + 2] = map_2a(data[0][i], data[1][i]);
}
}());
console.timeEnd('typed');
Is there anything I'm doing wrong?
I think your problem is that you are not comparing the same code. In the first example, you have one large array filled with very small arrays. In the second example, you have two very large arrays, and both of them need to be indexed. The profile is different.
If I structure the first example to be more like the second (two large generic arrays), then the Float32Array implementation far outperforms the generic array implementation.
Here is a jsPerf profile to show it.
In V8 variables can have SMI (int31/int32), double and pointer type. So I guess when you operate with floats it should be converted to double type. If you use usual arrays it is converted to doubles already.