I tried to define a 3D array on Google Sheet, but even though I'm using the .slice() method it keeps passing the array by reference.
var temp = [];
for (var a = 0; a<archetypesAll.length; a++) {temp[a] = [0, a].slice();};
var archRank = [];
for (var a = 0; a<21; a++) {archRank[a]= temp.slice();};
archRank[2][1][0] = 'Test';
I want to edit a single element of the matrix but instead the code above just fills every row with the exact same value ('Test'):
3DMatrix[x][1][0] = 'Test'
You can't just copy a multidimensional array by calling slice at the top level, because that will not deep-copy the whole. You have to write your own deepCopy methid, like this:
function allocate(mainDim, ...dims) {
const result = new Array(mainDim);
for (let i = 0; i < result.length; i++) {
result[i] = dims.length > 0 ? allocate(...dims) : 0;
}
return result;
}
function deepCopy(matrix, dims) {
return dims > 1 ? matrix.map(row => deepCopy(row, dims - 1)) : matrix.slice();
}
function test() {
const mx1 = allocate(3,2,2);
mx1[2][1][0] = "Test";
console.log(JSON.stringify(mx1));
const mx2 = deepCopy(mx1, 3);
mx2[2][1][0] = "Copied";
console.log(JSON.stringify(mx1));
console.log(JSON.stringify(mx2));
}
test();
var array = ["Test", "Test"];
var array3d = [[array.slice(0)],[[array.slice(0)]]];
array3d[0][0][0] = "Changed";
console.log(JSON.stringify(array3d)); //[[["Changed","Test"]],[[["Test","Test"]]]]
Try with this instead of slice to get a new array instead of reference:
var temp = [];
for (var a = 0; a < archetypesAll.length; a++) {
temp[a] = JSON.parse(JSON.stringify([0, a]));
}
var archRank = [];
for (var a = 0; a < 21; a++) {
archRank[a]= temp.slice();
}
archRank[2][1][0] = 'Test';
Related
I have this array of objects to count element frequency in another array using for loop which prints correct output.
counts = {};
counter = 0;
counter_array = [50,50,0,200]; //this is just for example, this array is filled dynamically
for (var x = 0, y = counter_array.length; x < y; x++) {
counts[counter_array[x]] = (counts[counter_array[x]] || 0) + 1;
}
console.log('FREQUENCY: ',counts); //outputs FREQUENCY: {50:2, 0:1, 200:1}
There is another array of arrays:
holder_text_array = [["a",50,0],["b",0,0]]; //example of dynamically filled array
var p = "a";
var i = 0;
while(i < holder_text_array.length){
if (holder_text_array[i][0]==p) {
var s = counts[holder_text_array[i][1]];
console.log('Element: ', holder_text_array[i][1]); //prints 50 for i = 0
console.log('frequency: ',counts[s]); //prints undefined
counter = counts[s];
}
i++;
}
The array of arrays "holder_text_array" consists of elements whose frequency I need to get in the while loop. Can someone tell me where am I wrong?
The frequency is stored in s not in counts[s]
You're logging counts[s] where var s = counts[holder_text_array[i][1]];
You've already got the element from counts in s. Just log the value of s
Apart from that the function works!
counts = {};
counter = 0;
counter_array = [50,50,0,200]; //this is just for example, this array is filled dynamically
for (var x = 0, y = counter_array.length; x < y; x++) {
counts[counter_array[x]] = (counts[counter_array[x]] || 0) + 1;
}
console.log('FREQUENCY: ',counts); //outputs FREQUENCY: {50:2, 0:1, 200:1}
holder_text_array = [["a",50,0],["b",0,0]]; //example of dynamically filled array
var p = "a";
var i = 0;
while(i < holder_text_array.length){
if (holder_text_array[i][0]==p) {
var s = counts[holder_text_array[i][1]];
console.log('Element: ', holder_text_array[i][1]); //prints 50 for i = 0
console.log('frequency: ', s); // CHANGED THIS TO JUST `s`
counter = counts[s];
}
i++;
}
You could take a recursive approach and call the count function again for (nested) arrays with the same counts object.
The result contains the counts of each element.
function getCounts(array, counts = {}) {
for (let i = 0; i < array.length; i++) {
const value = array[i];
if (Array.isArray(value)) {
getCounts(value, counts);
continue;
}
if (!counts[value]) counts[value] = 0;
counts[value]++;
}
return counts;
}
console.log(getCounts([["a", 50, 0], ["b", 0, 0]]));
I figured out the problem. Issue is in initialization.
I changed the following:
var s = counts[holder_text_array[i][1]];
counter = counts[s];
It works this way:
var s = holder_text_array[i][1];
counter = counts[s];
What I'm working on is a menu that auto updates its entries based on an array length. It adds groups of 10 objects' properties (in this case "IDnumbers") to the menu if a new object is added to the array.
var arraysOfObject = [], obj = {"IDNumber": ""};
for(i = 0; i<42; i++){
arraysOfObject.push({"IDNumber": "Number " + i});}
Above is the array holding 42 objects with a specific property.
var array2 = [];
var leftOver = arraysOfObject.length % 10;
var groupsOfTen = (arraysOfObject.length - leftOver)/10;
for (var i = 0; i < groupsOfTen; i++) {
array2.push([]);
for (var j = i*10; j < i*10 + 10; j++)
array2[i].push(arraysOfObject[j]["IDNumber"]);
}
//now the leftover
if (leftOver > 0) {
array2.push([]);
for (var i = groupsOfTen*10; i < arraysOfObject.length; i++)
array2[array2.length-1].push(arraysOfObject[i]["IDNumber"]);
}
The array2 above is the array that stores all the possible arrays that can be grouped by 10 from arraysOfObject. In this case there are 5 inside of it, because 4 arrays holds 40 objects, and 1 array holds the 2 remainders.
That all works fine, but placing the array2 inside the menu displays all possible IDnumbers grouped together, but not grouped individually. I have to declare each possible array inside of it like so sets = [array2[0], array2[1], array2[2], array2[3], array2[4]]; If there's a 6th possible array because object #51 has been added to arraysOfObject, I have to input it with array2[5].
I don't want it to depend on my input, but that it knows the number of possible arrays and that it displays it automatically in sets. How do I do that?
var gui = new dat.GUI();
var guiData = function() {
this.message = "Dat.Gui menu";
this.system = 0;
this.Sets = 0;
};
var data = new guiData();
sets = [array2[0], array2[1], array2[2], array2[3], array2[4], array2[5]];
gui.add(data, 'message', 'Dat.Gui Menu!');
gui.add(data, 'system', {
"1": 0,
"2": 1,
"3": 2,
"4": 3,
"5": 4,
"6": 5,
}).name('system #').onChange(function(value) {
updateSets(value);
});
gui.add(data, 'Sets', sets[0]).onChange();
function updateSets(id) {
var controller = gui.__controllers[2];
controller.remove();
gui.add(data, 'Sets', sets[id]).onChange();
data.Sets = 0;
gui.__controllers[2].updateDisplay();
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/dat-gui/0.6.1/dat.gui.min.js"></script>
<script>
var arraysOfObject = [], obj = {"IDNumber": ""};
for(i = 0; i<42; i++){
arraysOfObject.push({"IDNumber": "Number " + i});}
var array2 = [];
var leftOver = arraysOfObject.length % 10;
var groupsOfTen = (arraysOfObject.length - leftOver)/10;
for (var i = 0; i < groupsOfTen; i++) {
array2.push([]);
for (var j = i*10; j < i*10 + 10; j++)
array2[i].push(arraysOfObject[j]["IDNumber"]);
}
//now take care of the leftover
if (leftOver > 0) {
array2.push([]);
for (var i = groupsOfTen*10; i < arraysOfObject.length; i++)
array2[array2.length-1].push(arraysOfObject[i]["IDNumber"]);
}
</script>
Not the issue at hand, but I was playing around with the dat.gui as you posted it and was wondering if the dropdown could be refilled without removing/adding/etc. It seems to work with .options. (NB The initialization code makes heavy use of ES6, but can work without. The system menu is created dynamically from the sets array)
let arraysOfObject =Array.from({length:42}, (o,i) => "Number " + i),
ch =10, sets = Array.from({length:Math.ceil(arraysOfObject.length/ch)}, (a,i) => arraysOfObject.slice(i*=ch, i+ch));
var gui = new dat.GUI();
var guiData = function() {
this.message = "Dat.Gui menu";
this.system = 0;
this.Sets = 0;
};
var data = new guiData();
gui.add(data, 'message', 'Dat.Gui Menu!');
gui.add(data, 'system', sets.reduce((obj,s,i) => (obj[i+1] = i, obj), {})).name('system #').onChange(updateSets);
let controller = gui.add(data, 'Sets');
updateSets(0);
function updateSets(id) {
controller = controller.options(sets[data.Sets = id]);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/dat-gui/0.6.1/dat.gui.min.js"></script>
I think the easiest solution would be to use ES2015's spread operator which I don't know if you would want to use yet...
ES2015 method (demo)
sets = [...array2];
There are a few other changes in the demo to set the system variable
But after taking a closer look, you can optimize the code by using the method from this SO answer to chunk your array using slice(). Also, I'm not sure why an object was used to create array entries when it just ends up as a string... demo
var arraysOfObject = [],
system = {},
chunk = 10,
size = 92;
for (var i = 0; i < size; i++) {
arraysOfObject.push("Number " + i);
}
var sets = [];
var index = 0;
for (i = 0; i < size; i += chunk) {
sets.push(arraysOfObject.slice(i, i + chunk));
system[index + 1] = index++;
}
var gui = new dat.GUI();
var guiData = function() {
this.message = "Dat.Gui menu";
this.system = 0;
this.Sets = 0;
};
var data = new guiData();
gui.add(data, 'message', 'Dat.Gui Menu!');
gui
.add(data, 'system', system)
.name('system #')
.onChange(function(value) {
updateSets(value);
});
gui.add(data, 'Sets', sets[0]).onChange();
function updateSets(id) {
var controller = gui.__controllers[2];
controller.remove();
gui.add(data, 'Sets', sets[id]).onChange();
data.Sets = 0;
gui.__controllers[2].updateDisplay();
}
I am trying to create a function that will dynamically create objects on the fly based on the input number arguments, but I'm running into an issue with iterating over the Object.create() part. I don't know where to play my i in the for loop, but ideally I would have all the sportsCar objects stored in the sportArray. That is the target at least.
function car(doors, capacity, storage) {
this.doors = doors;
this.capacity = capacity;
this.storage = storage;
};
var van = Object.create(car);
van.doors = 4;
van.storage = "rear storage";
var miniVan = Object.create(van);
miniVan.capacity = "200 LB";
var cargoVan = Object.create(van);
cargoVan.capacity = "800 LB";
var truck = Object.create(car);
truck.doors = 2;
truck.storage = "bed";
truck.capacity = "1500 LB";
var familyCar = Object.create(car);
familyCar.doors = 4;
familyCar.storage = "large trunk";
familyCar.capacity = "300 LB";
var sportsCar = Object.create(car);
sportsCar.doors = 2;
sportsCar.storage = "small trunk";
sportsCar.capacity = '100 LB';
function tally(n1, n2, n3, n4, n5) {
var sportArray = [];
var familyArray = [];
var truckArray = [];
var miniArray = [];
var cargoArray = [];
sportsObjs = for(var i = 0; i < n1; i++){
Object.create(sportsCar);
}
sportArray.push(sportsObjs);
for (var i = 0; i < n2; i++){
Object.create(familyCar);
}
for(var i = 0; i < n3; i++){
Object.create(truck)
}
for(var i = 0; i < n4; i++){
Object.create(miniVan)
}
for(var i = 0; i < n5; i++){
Object.create(cargoVan)
}
return console.log(sportsArray);
}
sportsObjs = for(var i = 0; i < n1; i++){
Object.create(sportsCar);
}
sportArray.push(sportsObjs);
That's a plain syntax error. A loop is a statement in JavaScript, not an expression - it doesn't yield a value. You can't assign it to a variable. What you actually want is to assign each newly created object to the variable, and then push that particular new object to the array:
for (var i = 0; i < n1; i++){
var sportsObj = Object.create(sportsCar);
sportArray.push(sportsObj);
}
You need only to push objects in the array inside the loop:
function tally(n1, n2, n3, n4, n5) {
var sportArray = [];
var familyArray = [];
var truckArray = [];
var miniArray = [];
var cargoArray = [];
for(var i = 0; i < n1; i++){
sportArray.push(Object.create(sportsCar)); // To create a generic Object sportArray.push({});
}
.... // And so on for all the arrays
}
The problem is that you declared the different arrays as var so they are not visible outside the body of the function.
You need to return an object containg all the arrays, something like that:
function tally(n1, n2, n3, n4, n5) {
var sportArray = [];
var familyArray = [];
var truckArray = [];
var miniArray = [];
var cargoArray = [];
...
return {
sportArray: sportArray,
familyArray : familyArray,
truckArray: truckArray,
miniArray: miniArray,
cargoArray: cargoArray
}
}
So you can do something like:
var result = tally(3, 4, 5, 6, 7);
console.log(result.sportArray.length);
To be more succint with parameters:
function tally(parameters) {
...
for (var i = 0; i < parameters.n1; i++) {
...
}
...
}
Calling tally in this manner:
var result = tally({n1: 3, n2:4, n3:5, n4:6, n5:7});
I have 2 strings and I need to construct the below result (could be JSON):
indexLine: "id,first,last,email\n"
dataLine: "555,John,Doe,jd#gmail.com"
Result: "id:555,first:john,....;
What would be the fastest way of joining alternately those 2 strings?
I wrote this - but it seems too straight forward:
function convertToObject(indexLine, dataLine) {
var obj = {};
var result = "";
for (var j = 0; j < dataLine.length; j++) {
obj[indexLine[j]] = dataLine[j]; /// add property to object
}
return JSON.stringify(obj); //-> String format;
}
Thanks.
var indexLine = "id,first,last,email";
var dataLine = "555,John,Doe,jd#gmail.com";
var indexes = indexLine.split(',');
var data = dataLine.split(',');
var result = [];
indexes.forEach(function (index, i) {
result.push(index + ':' + data[i]);
});
console.log(result.join(',')); // Outputs: id:555,first:John,last:Doe,email:jd#gmail.com
If you might have more than one instance of your object to create, you could use this code.
var newarray = [],
thing;
for(var y = 0; y < rows.length; y++){
thing = {};
for(var i = 0; i < columns.length; i++){
thing[columns[i]] = rows[y][i];
}
newarray.push(thing)
}
source
Why is this code shown array[7][0] is undefined when it should have a value?
var tnotes = [];
var index = 0;
for (var i = 0; i < 14; i++) {
tnotes[i] = [];
}
var tx = 'B4';
var notes=['B5','A5','G5','F5','E5','D5','C5','B4','A4','G4','F4','E4','D4','C4']
var getNotes = notes.indexOf(tx);
if (getNotes != -1) {
tnotes[getNotes][index][] = new Array(20)
tnotes[getNotes][index][0] = tx //B4
tnotes[getNotes][index][2] = '3sec'
index++
}
console.log(tnotes[7][0])
You simply have a syntax error in defining one of your sub-arrays. The following line is incorrect:
tnotes[getNotes][index][] = new Array(20)
You are introducing a third-dimension of your tnotes array without it being defined
It should be:
tnotes[getNotes][index] = [];
Or if you really need the size parameter:
tnotes[getNotes][index] = new Array(20);
After this, tnotes[7][0] should no longer be undefined. Also, please do yourself a favor and make sure you use semi-colons consistently, it's good practice and can save you many-a-headache.
Corrected code:
var tnotes = [];
var index = 0;
for (var i = 0; i < 14; i++) {
tnotes[i] = [];
}
var tx = 'B4';
var notes = ['B5','A5','G5','F5','E5','D5','C5','B4','A4','G4','F4','E4','D4','C4'];
var getNotes = notes.indexOf(tx);
if (getNotes != -1) {
tnotes[getNotes][index] = [];
tnotes[getNotes][index][0] = tx; //B4
tnotes[getNotes][index][2] = '3sec';
index++;
}
console.log(tnotes[7][0]);