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.
Related
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'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.
I have an array of uniform objects:
var objects = [{
id: 1,
name: "one"
}, {
id: 2,
name: "two"
}];
And I'm converting these to a Map by using the id property of each object as Map keys:
var map = new Map();
objects.forEach(obj => map.set(obj.id, obj));
However, I'd like to do the conversion without:
having to manually create a new map object myself, and
having to manually iterate over the array and calling set myself
Additionally, I don't feel I should be making a utility function for this presumably native functionality.
Note: search queries for js array to map, or js convert array to map, or js map from array are all bloated with stone-age-era answers with Object, or solutions with a utility function. I'm looking for the native approach here.
I.e. I'm looking for the native JavaScript equivalent of mapping an array to a dictionary in C#, for example.
var map = list.ToDictionary(item => item.id);
This is so straightforward and convenient, yet interestingly enough, there is no Map.from in JavaScript (even though there is an Array.from).
I did my research while writing up the question, and I feel I should leave the solution here, as its possible practical applications are many.
I'm looking for the native JavaScript equivalent of mapping an array to a dictionary in C#
Considering a Map can be constructed with an iterable of 2-element arrays, where the first element of each inner array is used as the key, and the second element is used as a value, I believe this is the native JS equivalent, also the shortest:
new Map(objects.map(obj => [obj.id, obj]));
Live demo
When I running this code by node app.js
'use strict';
var data = {"456":"First","789":"Second","123":"Third"};
console.log(data);
I've geting next result:
{ '123': 'Third', '456': 'First', '789': 'Second' }
Why JS or Node.js (I don't know who) sort this object by keys? I don't want this.
What you're seeing is a behavior of the V8 JavaScript engine. It's not something specified by the JavaScript specification, and it's not something you can rely on (most engines don't do that).
But the important thing here is: There is no order to a JavaScript object. So V8's behavior is just as correct as putting those keys in any other order. If you want things in a particular order, you have to use an ordered container, like an array.
JavaScript objects aren’t ordered. If you want things in order, you can use an array.
var data = [
{ key: "456", value: "First" },
…
];
Or, alternatively, keep the key order in a separate array.
Properties in an object aren't ordered. You can't expect the order you give to be preserved when a representation of your object is built for the console.
The iteration order is implementation dependent. Don't rely on it. If you need some order, use another data structure (for example and array of key-values).
// try this to sort employees by age
employees.sort(function(a, b){
return a.age-b.age
});
Is there a way to do this out of the box with the _.sortBy method or any other part of the library?
You mean like this?
var array = [
{ name: "banana" },
{ name: "carrot" },
{ name: "apple" }
];
var sorted = _(array).sortBy("name");
I'd say it works out of the box.
If you wanted to sort an ordinary array of strings, you probably just want to use sort:
var flatArray = ["banana", "carrot", "apple"];
flatArray.sort();
See here. Also works.
Note that Underscore's sortBy returns a new array which is sorted, where JavaScript's built-in sort function sorts an array in place.
Since you tagged your question with the backbone.js tag, I'm assuming you mean to sort a collection, you just need to provide a comparator function on your collection and backbone will keep the collection sorted.
If your question is specifically alphabeticical sorting, I believe that is the default sort, from the backbone.js documentation (I linked to it above)
chapters.comparator = function(chapter) {
return chapter.get("page");
};