Below, I have an array of arrays of objects. I go through looking for my object, and once I find which array it's in, I want to get at and work with that array's name as a string. My guess, was something like Array.name (as it plays out below), but that doesn't work.
ActiveDocument.gaShapesTab1 = new Array(ActiveDocument.Sections["Dashboard"].Shapes["Shape1"],ActiveDocument.Sections["Dashboard"].Shapes["Shape2"]);
ActiveDocument.gaShapesTab2 = new Array(ActiveDocument.Sections["Dashboard"].Shapes["Shape3"],ActiveDocument.Sections["Dashboard"].Shapes["Shape4"]);
ActiveDocument.gaShapesTab3 = new Array(ActiveDocument.Sections["Dashboard"].Shapes["Shape5"],ActiveDocument.Sections["Dashboard"].Shapes["Shape6"]);
ActiveDocument.gaShapeArrays = new Array(gaShapesTab1, gaShapesTab2, gaShapesTab3);
// go through an array of arrays
for(var x=0; x<gaShapeArrays.length; x++)
{
// and go through the objects of each one
for(var y=0; y<gaShapeArrays[x].length; y++)
{
// if "object" is in the array
if(object == gaShapeArrays[x][y])
{
// get "sidetab" from object's array's name
var sidetab = gaShapeArrays[x].name.replace('gaShapes',''); // assumes that shapearrays will have naming convention gaShapesSidetab
// we found it, we can stop now
break;
}
}
}
I'm working in Hyperion Intelligence, so not all Javascript will apply. For instance I don't have access to window or document.
Each array contains a set of shape objects related to a visual tab. This allows me to show or hide or do more complex operation with what's on each tab simply by calling the array of shapes. But, when working with the shapes, themselves, I need to know which tab they're on. I'm trying to work backwards by finding which array they're in.
You don't want to do that.
If you really need to find a value in several arrays and then pull out an identifier, then you want a dictionary, not named variables:
var dictOfArrays = {
'evens': [0,2,4,6,8,10],
'odds': [1,3,5,7,9]
};
This stores the identifier that you seek as data, so you can store that identifier and use it later to retrieve the value if you want:
var whichArrayKey = findMyValuesKey(value, dictOfArrays);
console.log('Value '+value+' is in array keyed '+whichArrayKey);
var matchingArray = dictOfArrays[whichArrayKey];
var firstValueInMatchingArray = matchingArray[0];
The name of a variable is just something for you, the developer, to use to know which thing is which. It's just a handle for a place in memory where stuff is stored. As such, it doesn't mean anything to the code. If you actually want to use it in the program, then it is data, not code, and should be encoded in a data structure like a dictionary as above. That way you can pass the array or the identifier around as much as you please, and the behaviour of the code doesn't have to be tied to the names you give your variables.
Edit 1:
The newly added code, in dictionary form/object notation:
ActiveDocument.gaShapeArrays = {
'gaShapesTab1' : [
ActiveDocument.Sections["Dashboard"].Shapes["Shape1"],
ActiveDocument.Sections["Dashboard"].Shapes["Shape2"]
],
'gaShapesTab2' : [
ActiveDocument.Sections["Dashboard"].Shapes["Shape3"],
ActiveDocument.Sections["Dashboard"].Shapes["Shape4"]
],
'gaShapesTab3' : [
ActiveDocument.Sections["Dashboard"].Shapes["Shape5"],
ActiveDocument.Sections["Dashboard"].Shapes["Shape6"]
]
}
So each key (e.g. 'gaShapesTab1') is paired with an array value ([...]). This is instead of using new Array() everywhere.
Once you have found the key of the array containing a reference matching your object, you'll have that key as a string (e.g. "gaShapesTab3"). You can't change this string in-place, and I don't think you'd want to. If you could clarify why you need to change the name of the array, perhaps it will be clear how to resolve the problem. For example, do you have other code that needs the array to have a particular name?
Array's name? Arrays do not have names. You only have variable names, variables that store your arrays. If you have a two-dimensional array, you need to grab the "coordinates".
So:
if(object == gaShapeArrays[x][y])
{
// Found the object! It's in [x][y], so in array gaShapeArrays[x] which
// itself is in gaShapeArrays
}
Even though I think #Phil H gave me the answer to my question, as the proper way to do it, I have other reasons to do it the way #ben336 was commenting. It might not be proper, but I'm posting what the solution was in the end. Fortunately, I already had the gaSidetabs array elsewhere in my startup script for another function. I just assigned a string value to the .name property of each array. Would've been nice to know if there was a way to "get at" the symbolic name (or whatever you want to call it) that I called the array, but it sounds like that's just not possible.
ActiveDocument.gaShapesTab1 = new Array(ActiveDocument.Sections["Dashboard"].Shapes["Shape1"],ActiveDocument.Sections["Dashboard"].Shapes["Shape2"]);
ActiveDocument.gaShapesTab2 = new Array(ActiveDocument.Sections["Dashboard"].Shapes["Shape3"],ActiveDocument.Sections["Dashboard"].Shapes["Shape4"]);
ActiveDocument.gaShapesTab3 = new Array(ActiveDocument.Sections["Dashboard"].Shapes["Shape5"],ActiveDocument.Sections["Dashboard"].Shapes["Shape6"]);
ActiveDocument.gaShapeArrays = new Array(gaShapesTab1, gaShapesTab2, gaShapesTab3);
ActiveDocument.gaSidetabs = new Array('Tab1','Tab2','Tab3');
// Assigns a .name javascript property to each array. assumes the order and length of the arrays is the same.
if (gaShapeArrays.length == gaSidetabs.length)
{
for (var x = 0; x < gaShapeArrays.length; x++)
{
gaShapeArrays[x].name = gaSidetabs[x];
}
}
else
{
Console.Writeln('Warning: gaShapeArrays and gaSidetabs are not the same length. Some names will not be assigned.');
}
// go through an array of arrays
for(var x=0; x<gaShapeArrays.length; x++)
{
// and go through the objects of each one
for(var y=0; y<gaShapeArrays[x].length; y++)
{
// if "object" is in the array
if(object == gaShapeArrays[x][y])
{
// get "sidetab" from object's array's name
var sidetab = gaShapeArrays[x].name.replace('gaShapes',''); // assumes that shapearrays will have naming convention gaShapesSidetab
// we found it, we can stop now
break;
}
}
}
Alert(sidetab);
Also glad I could figure out how to retain the format of the code block, here.
Related
Newbie here...be nice.
I have an empty object that will get pushed into an array.
listView = {};
I add properties to it.
listView.code = code;
listView.description = description;
I push the results object into an array.
listy.push(listView);
Each time I enter a new selection in step #2 it overwrites the object instead of adding the new object properties to the array. It also increments the index by one, so it just repeats...
[{"code":"I77.812","description":"Thoracoabdominal Aortic Ectasia"}]
[{"code":"I77.811","description":"Abdominal Aortic Ectasia"},{"code":"I77.811","description":"Abdominal Aortic Ectasia"}]
[{"code":"I06.1","description":"Rheumatic aortic insufficiency"},{"code":"I06.1","description":"Rheumatic aortic insufficiency"},{"code":"I06.1","description":"Rheumatic aortic insufficiency"}]
The array should contain three different objects. But instead it has three copies of the newly added one...
How should I be adding the new choice objects so that they don't get overwritten?
You are always adding a reference to the same object, and changing that same object, instead of adding new objects. See this:
var a = [];
var o = {};
for (var i = 0; i < 5; i++) {
o.id = i;
a.push(o);
}
a
// => [{"id":4},{"id":4},{"id":4},{"id":4},{"id":4}]
But
var a = [];
for (var i = 0; i < 5; i++) {
var o = {};
o.id = i;
a.push(o);
}
a
// => [{"id":0},{"id":1},{"id":2},{"id":3},{"id":4}]
The difference is, the second code always makes a new object that is distinct from all other objects already in the array.
As a metaphor, imagine a theatre director in casting. He turns to an actor, says "You... you'll be Romeo.". Then he looks at the same actor, says "You... you'll be Mercutio. Here, Mercutio, take this sword. Romeo... who told you to get a sword?!?" completely failing to realise that, if Romeo and Mercutio are the same person, if one of them picks up a sword, the other does it too.
Seeing as you declared yourself a 'newbie' i figured i'd take a bit more time explaining. When you push an object to an array, you don't copy the object. You just tell the array where to find the object (a reference). If you push the same object 3 times, the array just has 3 indexes at which it finds the same object. There's several ways around this, the easiest being that you declare the variable inside the loop
for (var i=0;i<3;i++){
var listView = {};
listView.id = i;
listy.push(listView);
}
This way listView is a different reference each time. The other way is to create a new object when you push
listy.push({id:listView.id, description:listView.description});
which works because simple variables are 'copied' into the array and not referenced.
your assignment of the properties of an object are simply replacing the existing properties. wh en you push the object in the array by name, you are push a reference to the object and not a value. This is why all the elements in the array are the same. You need to create a new object every time you push. Something like this should work for you.
listy.push({code:code, description:description});
try this :
listy.push({
code:listView.code,
description : listView.description
})
In my code I have used pass by value.
In your code , you are using Objects which are passed by reference .
You are adding same reference again and again so at the end you will get an array having all the values of same object .
To understand more about pass by value and pass by reference you can reffer this link :
Pass Variables by Reference in Javascript
I'm working with phylogentic trees and I want an object for the tree itself and then an object for each species, 4 species total. I'm trying to have the tree contain the species objects under tree.leaf and then assign an array of attributes to each species but through the tree object, because I'm randomizing the order of the species so I can't depend on species names but I can use leaf placement(Hope that makes sense). I'm having trouble updating the html, a div inside a table though.
Simplified Version:
var tree = new Object();
var speciesA = new Object();
tree.leaf1 = speciesA;
//Not sure if this next line assigns to speciesA or what exactly happens
tree.leaf1.attributes = new Array("Attr1","Attr2",etc);
var count = 1;
for(attr in speciesA.attributes)
{
//There are 4 divs per speices to display attributes
document.getElementById("A"+String(count)).innerhtml = speciesA.attributes[attr];
count++;// used to specify divs ie A1 = attribute1, A2 = attribute2 etc
}
So I guess my main question is will this work/do what I think it does?
If needed I can pastebin my html and full js files.
What you have should work, but it can be written a bit cleaner. I would suggest this:
var tree = {
leaf1: {attributes: ["Attr1", "Attr2"]}
};
var attributes = tree.leaf1.attributes;
for (var i = 0; i < attributes.length; i++) {
document.getElementById("A"+(i+1)).innerHTML = attributes[i];
}
Things I changed:
Used a javascript literal to make the definition a lot more compact
Used {} and [] for defining arrays and objects rather than new Object() and new Array().
Used for (var i = 0; i < xxx.length; i++) syntax to iterate array elements only, not all properties. This is the "safe" way to iterate elements of an array.
Remove the String(count) as it is not needed. Javascript will auto-convert a number to a string when adding to another string.
Cached the value of the attributes array to save having to deep reference it each time.
Removed separate count variable as the for index can be used
To answer one of your other questions, when you do this:
tree.leaf1 = speciesA;
you have assigned a "reference" to speciesA to tree.left1. A reference is like a pointer. It is not a copy. So, the both refer to exactly the same object. Any change you make to speciesA or to tree.leaf1 is make a change to the exact same object.
So, when you then do this:
//Not sure if this next line assigns to speciesA or what exactly happens
tree.leaf1.attributes = new Array("Attr1","Attr2",etc);
you are indeed modifying the speciesA object since speciesA and tree.leaf1 point to the same object.
In javascript, arrays, objects and strings are assigned by reference. That means that when you assign one to a variable, it just points to the original object. A copy is not made. So, change the object via either either one will change the other (since they both point to the same object). Strings are immutable (a string is never actually changed). Things that feel like modifications to a string always just return a new string so this aspect of javascript doesn't affect strings so much. But, it is very important to know that arrays and objects are assigned by reference.
I have some simple Javascript looping through an array of items (Tridion User Groups) to check if the user is a member of a specific group.
I can easily code around the issue shown below ( see && extensionGroup !== 'true') but I want to understand why the isArray = true is counted as a value in the array - any ideas?
The screenshot below demonstrates that the value extensionGroups has been set thus
var extensionGroups = ["NotEvenARealGroup", "Author", "ExampleGroupAfterOneUserIsActuallyIn"];
but returns the isArray value as a 4th value?
updated to show images a little clearer
You're using for in to iterate an array; don't do that. Use for (or forEach):
for(var i = 0; i < extensionGroups.length; i++) {
var extensionGroup = extensionGroups[i];
// ...
}
The reason this fails is because for in is used to iterate over an object's properties in JavaScript. Iterating over an array in this way means you get anything else assigned to it, such as this property or length.
And if you're able to use Array#forEach, it's probably most appropriate here:
extensionGroups.forEach(function(extensionGroup) {
// ...
});
For..in, technically speaking, doesn't iterate through values. It iterates through property names. In an array, the values ARE properties, under the hood. So when you iterate over them with for..in you get funky stuff like that happening.
Which highlights my next point: don't use for..in. Don't use it for arrays -- don't use it for anything, really. Ok -- maybe that's going a bit too far. How about this: if you feel the need to use for..in, think hard to see if it's justifiable before you do it.
I am a bit confused at this point on what is an object, what is an array, and what is a JSON. Can someone explain the differences in syntax between the two? and how to add items to each, how to merge each type, and such? I am trying to get this function to take the new information from a JSON object (I think) and merge it with some new information. This information will then be passed to a PHP script to be processed.
Here is the console output:
{"public":{"0":["el29t7","3bmGDy"]}}
{"public":"[object Object][object Object]"}
Here is the JS I am using:
/* Helper function to clean up any current data we have stored */
function insertSerializedData(ids, type) {
// Get anything in the current field
current_data = $('#changes').val();
if (!current_data) {
var data = {};
data[index++] = ids;
var final_data = {};
final_data[type] = data;
$('#changes').val(JSON.stringify(final_data));
} else {
current_data = JSON.parse(current_data);
var data = {};
data[index++] = ids;
// Does the index exist?
if (type in current_data) {
var temp_data = current_data[type];
current_data[type] = temp_data + data;
} else {
current_data[type] = data;
}
//var extra_data = {};
//extra_data[type] = data;
//$.merge(current_data, extra_data);
$('#changes').val(JSON.stringify(current_data));
}
console.log($('#changes').val());
}
The idea is if the key (public, or whatever other ones) doesn't exist yet, then to make it point to an array of arrays. If it does exist though, then that of array of arrays need to be merged with a new array. For instance:
If I have
{"public":{"0":["el29t7","3bmGDy"]}}
and I want to merge it with
["aj19vA", "jO71Ba"]
then final result would be:
{"public":{"0":["el29t7","3bmGDy"], "1":["aj19vA", "jO71Ba"]}}
How can i go about doing this? Thanks
Excellent two-part question. Overall, the second question is non-trivial because of the complexity of the first.
Question 1:
what is an object, what is an array, and what is a JSON. Can someone
explain the differences in syntax between the two?
Question 2:
and how to add items to each,
Question 3:
how to merge each type, and such?
Answer 1:
This is a common stumbling point because, JavaScript is more flexible than one might initially expect. Here is the curve.
In JavaScript everything is an object.
So here is the code for each:
//What is an object?
var obj = { };
var obj2 = { member:"value", myFunction:function(){} }
Above is an empty object. Then another object with a variable and a function.
They are called object-literals.
//What is an array
var array1 = [ ] ;
var array2 = [0,1,2,3,4];
Above is an empty array. Then another array with five Integers.
Here is the curve that causes confusion.
//Get elements from each of the prior examples.
var x = obj2["member"];
var y = array2[1];
What??? Both Object and Array are accessing values with a bracket?
This is because both are objects. This turns out to be a nice flexibility for writing advanced code. Arrays are objects.
//What is JSON?
JSON stands for JavaScript Object Notiation. As you might have guessed. Everything is an object... It is also an { }; But it is different because - it is used to transfer data to - and - from JavaScript, not actually used (commonly) in JavaScript. It is a file transfer format.
var JSONObject = {"member":"value"};
The only difference to the prior example is quotes. Essentially we are wrapping the object literal as a string so that it can be transferred to a server, or back, and it can be reinterpreted, very easily. Better than XML - because it does not have to be custom-parsed. Just call, stringify() or ParseJSON(). Google it. The point is... JSON can be converted into an object-literal JS object, and JS object-literals can be converted into JSON, for transfer to a server or a CouchDB database, for example.
Sorry for the tangent.
Answer 2:
How to add an item to each? Here is where the curve stops being a nuisance, and starts being awesome! Because everything is an object, it is all just about the same.
//Add to an object
var obj {member1:"stringvalue"}
obj.member2 = "addme"; //That is it!
//Add to an array
var array1 [1,2,3,4,5];
array1[0] = "addme";
array[6] = null;
//We shouldn't mix strings, integers, and nulls in arrays, but this isn't a best-practice tutorial.
Remember the JS object syntax and you may start to see a whole new flexible world of objects open up. But it may take a bit.
Answer 3: Ah, yeah... how to merge.
There are seriously (very many) ways to merge two arrays. It depends on exactly what you need. Sorted, Duplicated, Concatenated... there are a few.
Here is the answer!
UPDATE: How to make a beautiful multiple dimensional array.
//Multiple Dimension Array
var array1 = [1,2,3];
var array2 = [3,4];
var arraysinArray = [array1,array2]; //That is it!
Here is the curve again, this could be in an object:
var obj{
array1:[1,2,3],
array2:[3,4]
}
JavaScript is powerful stuff, stick with it; it gets good. : )
Hope that helps,
All the best!
Nash
In this case, think of a JavaScript's object literal {} as being like PHP's associative array.
Given that, an "array of arrays" actually looks like this (using your above desired output):
{public: [["el29t7","3bmGDy"], ["aj19vA", "jO71Ba"]]}
So here we have an object literal with a single property named "public" whose value is a 2-dimensional array.
If we assign the above to a variable we can then push another array onto "public" like this:
var current_data = {public: [["el29t7","3bmGDy"], ["aj19vA", "jO71Ba"]]};
// Using direct property access
current_data.public.push(["t9t9t9", "r4r4r4"]);
// Or using bracket notation
current_data["public"].push(["w2w2w2", "e0e0e0"]);
current_data's value is now:
{public: [
["el29t7","3bmGDy"],
["aj19vA", "jO71Ba"],
["t9t9t9", "r4r4r4"],
["w2w2w2", "e0e0e0"]
]}
So now "public" is an array whose length is 4.
current_data.public[0]; // ["el29t7","3bmGDy"]
current_data.public[1]; // ["aj19vA", "jO71Ba"]
current_data.public[2]; // ["t9t9t9", "r4r4r4"]
current_data.public[3]; // ["w2w2w2", "e0e0e0"]
MDN has very good documentation on Array for insight on other functions you might need.
https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array
First is an object, that contains array, second is an array.
DEMO showing display output http://jsfiddle.net/GjQCV/
var object={"public":{"0":["el29t7","3bmGDy"]}};
var arr=["aj19vA", "jO71Ba"] ;
/* use object notation to add new property and value which is the array*/
object.public[1]=arr;
It'd be much more natural if {"0": ...} were a true array rather than an object, but anyway:
function maxKey(b) {
var max;
for( var key in b )
var max = key;
return max;
}
function merge(a,b) {
for( var key in a ) {
b[key] = b[key] ? (b[key][maxKey(b)+1]=a[key], b[key]) : a[key];
}
return b;
}
Note that this assumes you would insert at the next integer index
Arrays are a particular kind of Javascript object
JSON is a way of representing Javascript objects (and as such can represent arrays and more)
Objects are much more general, and can be simple objects that can be represented as JSON, or can contain functions and prototypes.
So, this is not an array of arrays (you would access items using JSON notation like myobj["0"]):
{"0":["el29t7","3bmGDy"], "1":["aj19vA", "jO71Ba"]}
This is an array of arrays, which means you can use the push method to add an item, and access items using array notation like myobj[0]:
[ ["el29t7","3bmGDy"], ["aj19vA", "jO71Ba"] ]
It seems like the structure you want is something like this:
var myobj = { "public": [ ["key", "value"], ["key", "value"] ] }
Then if you want to add/merge new items, you'd write this:
if (myobj["public"] != null) {
myobj["public"].push(["newkey", "newval"]);
} else {
myobj["public"] = ["newkey", "newval"];
}
Doing so
var x = new Array();
x['length']=5;
will make x an array of 5 undefined items, but I actually want to have the value '5' stored at key 'length'.
Is that possible?
In javascript arrays do not have keys. You are looking for objects:
var x = {}
x.length = 5;
I have to parse a file containing many words and store the number of occurences of each word
Use an object, and make the words the keys. You aren't storing sequential / ordered data, so you shouldn't use an array.
var word_count = {};
for (var i; i < words.length; i++) {
var word = words[i];
if (word_count[word]) {
word_count[word]++;
} else {
word_count[word] = 1;
}
If you want to do this you'd be better off creating an object rather than an array. This should give you what you want.
var x = {};
x['length'] = 5;
You can call methods on a javascript object using two different syntaxes. The familiar 'dot' syntax with parens to invoke the method, and the square bracket syntax. You can 'call' a method on a javascript object using the syntax myObj["methodname"](args). This is handy when you want to construct the method name dynamically using strings. Remember, objects in javascript are very much like a hash table (dictionary) where keys denote property and function names. If a key's value holds a function, it can be invoked (using parentheses).
In your example, Array has a method called 'length'. You are inadvertently calling its setter (which sets the length of the array to empty values, i.e., undefined).
Putting that all aside, you really do want a hash (associative array) in this case. An array is an offset indexed data structure.
A simple object literal like myObj = {} will suffice to give you hash semantics (again, objects in javascript are already like hashes) and you can then call myObj.whatever = "some value"
You could use objects instead of arrays to store your data. But if you need to use Arrays (you might need to use their functionality), You could cripple the words and store them as array keys.
Use some kind of simple rule to follow to bypass all the possible keywords. For example prefix all your array keys with a "_" character. This way you could always restore the original words from the keys, by simply removing their first character, and you are sure you are not referencing any specific property of the Array objects (like the length property).