i'm struggling with declaring and accessing data in nested arrays in Javascript
i can easily do it in C using nested structures, declaring first the lowest-level structure and including an array of it when declaring the upper-level structure and so on. I end up with a structure containing an array of structures, each containing an array of structures, etc...
but i have only 3 days of Javascript experience so far...
Just to help you understand how i need the data to be organized, here's an example:
Let's imagine a library, this library has several floors, each floor has the same type of properties (name, number of books...), each floor has several departments and each has the same type of properties, each department has several shelves and so on...
let's say the 1st floor get's its name from some famous mathematician, and is split into two departments: 1/ arithmetics and 2/ geometry
the ideal for me would be to work with the data this way:
library.floor[0].name = 'Fermat'
library.floor[0].department[0].name = 'arithmetics'
library.floor[0].department[1].name = 'geometry'
library.floor[0].department[1].shelve[4].authors = // authors list
so far i've tried this:
var library =
{
floors: [
{floor_name:'Fermat'},
{has_a_printing_machine:true},
{departments:[
{department_name:'group_theory'},
{shelves:[
{shelf_name:'letters_f_z},
{authors: ["Frobenius","Lagrange"]}]}]}]
};
i can get data from:
log(library.floors[0].floor_name); // ouputs 'fermat'
log(library.floors[2].departments[0].department_name); // outputs 'group_theory'
log(library.floors[2].departments[1].shelves[1].authors[1]); // outputs 'Lagrange'
but it isn't what i need, i can't access a 'departments' property for each floor for instance... and i'd like to add data dynamically in these arrays.
i'm doing it wrong and i can't figure out how to do it right...
thanks for your help!
You're misunderstanding JavaScript object literals. They are completely different that structs in C. Structs are type declarations, JavaScript object literals are actual objects.
You should stop putting one key/value pair per object, and start making uniform objects that contain the same attributes.
When you write [ { department_name: ... }, { shelves: ... } ] you are defining an array that contains two unrelated objects, one containing a department_name property, and the other containing a shelves property. These objects know nothing about each other, or that they are contained in the same array.
Instead of this...
[
{
department_name: 'group_theory'
},
{
shelves: [
{
shelf_name: 'letters_f_z'
},
{
authors: ["Frobenius","Lagrange"]
}
]
}
You should be writing:
{
departments: [
{ # This entire object is a department. It has a name and shelves
name: 'group_theory',
shelves: [
{ # This entire object is a shelf. It has a name and authors.
name: 'letters_f_z',
authors: ["Frobenius","Lagrange"],
}
]
}
]
}
To put it a different way, when you write this...
floors: [
{floor_name:'Fermat'},
{has_a_printing_machine:true},
{departments:[...]}
]
You are not making an array of floors, you're making an array of three totally unrelated objects, one that contains a floor_name property, one that contains a has_a_printing_machine property, and one that contains a departments property. If you want all three objects to have all three properties, you need to declare them that way:
floors: [
{ name: 'floor_one', has_a_printing_machine: true, departments: [] },
{ name: 'floor_two', has_a_printing_machine: false, departments: [ ... ] },
{ name: 'floor_three', has_a_printing_machine: true, departments: [] },
]
You almost had it. Each floor is an entity on its own, with its properties. One of its properties is the list of departments, and each department is an entity itself too (again, with its own properties). And same with the shelves.
Each instance of an entity/struct/register is a dictionary, with its properties mapped as key:value pairs. So, for instance, a shelf could be:
var my_shelf = {
shelf_name:'letters_f_z',
authors: ["Frobenius","Lagrange"]
};
A department (with its shelves) may be:
{
department_name:'group_theory',
shelves:[
{
shelf_name:'letters_f_z',
authors: ["Frobenius","Lagrange"]
},
{...}
]
}
I think at this point you can extrapolate this construction to the floors level, having an array of department registries as the value of the departments property.
Unfortunately, unlike TypeScript, which is a statically-typed superset of JavaScript, you can't enforce each register to actually have a certain set of properties. So you'll have to be extra-cautious when creating the instances so every property is initialized since its very beginning.
Related
We're building a dynamic JSON payload according to a simple template format that instructs how many levels our payload should produce, e.g. "level1.level2" > will produce:
{
"level1": [
{
"level2": [
{
"someData": "willGoHere",
},
{
"someOtherData": "willAlsoGoHere"
}
]
}
]
}
Obviously we're working with a different naming structure, e.g: "client.ipcEvent.level3" and in some cases we're testing 4 levels. We're doing something wrong ~ we're able to build our javascript object but unable to use stringify() to create a full result because for some strange reason stringify() against our object only returns the 1st level's data:
{ "level1": [] }
.
I've tried changing the way in which our object is loaded with values but it all comes back to stringify() 'dropping' off array values that don't have accompanying attribute/property values at the same level.
The issue is that your client is an array, but you've put properties on it that aren't array entries (which you can do because arrays are objects):
JSON.stringify only includes the array entries of an array, not its other properties:
const a = [];
a.nonEntryProperty = "foo";
a[0] = "bar";
console.log(JSON.stringify(a)); // ["bar"]
To ensure data is serialized to JSON correctly, include object-like properties in objects, and array entries in arrays:
const structure = {
info: {
nonEntryProperty: "foo"
},
array: ["bar"]
};
console.log(JSON.stringify(structure, null, 4));
OK, solved; we were creating arrays when it should have been objects, and vice-versa; sorry for the vague question but thank you TJ and Sebastian. Based on the specification of "level1.level2" the solution was to create object {} for "level1" and array [] for the last item "level2"...
I have two variants to work with my objects full of data:
let global_obj = {
"id0": { /*big object 0*/},
"id1": { /*big object 1*/},
"id2": { /*big object 2*/}
};
and:
let global_arr = [
{ id: "id0" /*big object 0*/},
{ id: "id1" /*big object 1*/},
{ id: "id2" /*big object 2*/}
];
So I can save my big objects full of data inside of a global array or a global object. Which way is better in terms of performace (looping through, deleting, adding new objects)?
I am going to address specific objects by their id very often, change objects' properties, loop trought them all.
I would use an object in this case as finding an element by id is easier/faster. If index/order of elements is important, object don't help here and you need to use an array.
Basically:
Objects: Keyed collections
Arrays: Ordered collections
But regular objects and arrays are not the only options if the environment supports ES2015. ES2015 has introduces several APIs for working with collections: Map, Set, WeakMap and WeakSet.
As you mentioned that you'll be "addressing specific objects through their id's very often"; using an Object will be a wise choice for you. Since accessing an object's key is done in O(1) as compared to finding the object in an array, which will be O(n), hence Object will be better in performance.
You should do what's more convenient for you, it most likely won't make a difference.
However, generally, if the top level object is small, the array is always faster than a hashtable/object (the size of the inner objects doesn't matter). If the top-level structure is big, then you should consider the big-o complexity for the operations you want to perform on the top-level structure. See http://bigocheatsheet.com/
I have a class (LiveScript) that is instantiated once, but its render method is called many times. Each object created in the render method must have a unique key that stays the same across all invocations of render:
class Test
->
console.log 'constructor, called only once'
render: ->
test = {key: 4124312}
test1 = {key: 234897}
test2 = {key: 87234}
This works, but instead of hardcoding the key I'd rather generate it. Using a random number will not work since that will generate a new key on each invocation of render. Having some list of keys outside this class and popping items of them won't work either because the order of the created objects in render could change. Any idea if and how I could generate the keys?
Generating them is one thing - it sounds like you need a way to persist the unique objects with a key that doesn't change during your execution context. This is called persistence.
In JS, you can use an object literal to store your objects, where the key of each entry in your storage object is the unique key of your stored objects:
{
1234: { name: "test", key: 1234 },
2345: { name: "test1", key: 2345 },
3456: { name: "test2", key: 3456 }
}
I am reading through Eloquent JavaScript and have been stuck trying to understand lists for about two days so I figured I would finally ask a question. The example they give in the book is:
var list = {
value: 1,
rest: {
value: 2,
rest: {
value: 3,
rest: null
}
}
};
Now I think I understand the example... There is a list object and it has properties value and rest. Then, rest has properties of value and rest, etc... However, I don't understand what rest is or even stands for. Does the rest property contain an object? So, list.rest.value would == 2? How is this useful? Some ways I could see this as useful are having a list Car, with prop engine, gauge, etc, with further properties of accelerate, brake, low fuel... How would something like this be achieved?
I do apologize for the "all overness" of this post, I don't exactly know what to ask or how to phrase it. It seems like the book only explained objects and properties, but never actually having objects as an objects property.
Thank you all in advance, and if you need any clarification or more info I will try to provide it.
This code simply uses JavaScript Object Notion to define an object named list.
// Would simply define an empty object.
var list = {};
Now you can add some properties to the object.
// Would define an object with a single property: `value`.
var list = {
value: 1
};
Using nested object declarations, you can give the list object child objects as well:
var list = {
value: 1,
rest: {}
};
Now list.rest is an empty object. You can fill that out by adding some properties:
var list = {
value: 1,
rest: {
value: 2
}
};
And your nesting can continue ad-infinitum. The object in your original post, the following is possible:
console.log(list.value); // 1
console.log(list.rest.value); // 2
console.log(list.rest.rest.value); // 3
It's important to understand that this in no way creates a class or includes any additional methods with the object. It seems to be structured as a linked list but provides no functionality to add/remove/modify (except by directly modifying the original object).
In the example above the list variable is an associative array. This is JavaScript's version of an "object". While the property list.value ends up being typed as an integer, the property list.rest is typed as a nested associative array. The properties themselves can be any valid type. Many jQuery plugins are coded where the properties themselves are actually delegate functions.
The object you have described above in the example does not seem to me to be terribly useful beyond being an example of how this kind of object can contain references to other objects. However, when you begin applying this in an "object oriented" concept (keep in mind that it is not truly object oriented), it becomes more useful. You can then create your own "namespace" with properties, functions and delegates that can be re-used time and again.
Thank you all for your information. I don't know if there is a best answer selection on this site or not, but I really do appreciate the help Justin, Joel, and Evan. I think the main part I was confused about is just practical application for real applications. I have messed around a little bit and came up with this and have a much better basic understanding now:
var car = {
engine: {
turn_on: "Turned engine on",
turn_off: "Turned engine off",
desc: {
size: "V6",
year: 2000
}
},
fuel: {
level: 55
}
};
function CheckFuel(fuel){
if(fuel > 50){
console.log("In good shape");
}
else{
console.log("We should fuel up");
}
}
console.log(car.engine.turn_on);
console.log(car.engine.turn_off);
console.log(car.engine.desc.size);
console.log(car.engine.desc.year);
CheckFuel(car.fuel.level);
Now time to practice iterating through. Thanks again!
This is an implementation of a linked list. Each node in the list has a reference to the next node. 'Rest' is an object (the next node in the list) that also contains every other node in the list (via it's rest property).
The first value in the list would be list.value;. The second value in the list would be list.rest.value;. The items in the list can be shown as:
item1 = list;
item2 = list.rest;
item3 = item2.rest;
This continues until itemX.rest is null.
These two functions could be used to manage the list and may help you understand how iterating through it would work:
function addToList(item)
{
if(!list)
{
list = item;
return;
}
var temp = list;
while(temp.rest)
{
temp = temp.rest;
}
temp.rest = item;
}
function printList()
{
var temp = list;
while (temp)
{
print temp.value; //i'm not sure what the javascript print function is
temp = temp.rest
}
}
The add function would be called like this: addToList({ value:10, rest:null });
I'm a student and new to Angular, so I apologize if this is obvious.
I see Angular used frequently for displaying lots of data. From what I've seen, it works fantastically when your data is stored as an array, but only puts up a fight when you try to use it with an associative array (Possible, but requires work-arounds).
Scenario:
I've got an array of kittens:
var kittens = [
{
id: "id0",
breed: "persian",
name: "Mr. Cuddles"
},
{
id: "id1",
breed: "siamese",
name: "Puddin' Face"
},
{
id: "id2",
breed: "ragamuffin",
name: "Rumblemuffins"
}
];
And there are a lot of kittens. I have an angular factory kittenService that retrieves this data from an API and maintains this array. I need the ability to look up these kittens by id and filter by breed. I turned this into an associative array with id as the key, but then I run into issues with $filter, etc. There isn't as much documentation for associative arrays, and it all seems just easier to implement using regular arrays.
tl;dr
If AngularJS is used to act on data, Why are associative arrays not as common in AngularJS applications? Should I think differently about data storage when using Angular?
You cannot refer to (what you are calling an array but in reality are objects aka hashes) associative arrays by index and you cannot do things like check the length property. My guess is it is much more efficient to work on actual arrays than to pretend that object hashes are arrays.