Accessing associative array inside an object - javascript

I have looked everywhere for this but nobody seems to use associative arrays in objects. Here is my object:
var player = {
Level: 1,
Stats: [{Defense : 5}, {Attack: 1}, {Luck: 3}]
};
I need to access the values of Defense, Attack, and Luck, but how?
I have tried this but it hasn't worked:
player.Stats.Defense
player.Stats.Attack
player.Stats.Luck
Any ideas? Thanks!
P.S. Does it make a difference that I am using jQuery?

You've said you're in control of the structure. If so, change it to this:
var player = {
Level: 1,
Stats: {Defense : 5, Attack: 1, Luck: 3}
};
Note that Stats is now an object, not an array. Then you access that information the way you tried to, player.Stats.Defense and so on. There's no reason to make Stats an array of dissimilar objects, that just makes your life difficult.
You've used the term "associative array" which makes me think you have a PHP background. That term isn't commonly used in the JavaScript world, to avoid confusion with arrays. "Object," "map," or "dictionary" are the terms usually used, probably in that order, all referring to objects ({}). Probably nine times out of ten, if you would use an associative array for something in PHP, you'd use an object for it in JavaScript (in addition to using objects for the same sort of thing you use objects for in PHP).
P.S. Does it make a difference that I am using jQuery?
No, this is language-level rather than library-level, but it's a perfectly reasonable question.
(Making this a CW answer because it's basically what all the comments on the question are saying.)

as Stats: [{Defense : 5}, {Attack: 1}, {Luck: 3}] is array of objects, you need to do:
player.Stats[0].Defense
player.Stats[1].Attack
player.Stats[2].Luck

Here player.Stats is an array of objects. So you'll have to use index for accessing those objects.
var player = {
Level: 1,
Stats: [{Defense : 5}, {Attack: 1}, {Luck: 3}]
};
Use these :
player.Stats[0].Defense
player.Stats[1].Attack
player.Stats[2].Luck

Related

how can I destructure from an array of objects when data is coming from database dynamically?

// foodItems is an array of object where one of it's key is id.
const [id1, id2, id3] = foodItems.map((item) => item.id);
// console.log(id1, id2, id3);
I can get id's by destructuring when array is static by doing above's code. But, How can I get the same id's when the data is coming from database dynamically in this array?
Edit: As Bergi pointed out: this horrible abomination does not even work if used in a different scope than root. But again, even if it had worked, don't do it like that.
Can you try to explain what you are really trying to do with that? Then we might be able to suggest a proper solution.
Old answer for historical reasons:
I don't really know you use-case for this but it generally seems like a bad idea. This is a poor pattern, do not use it, but it should answer your question anyways. So here is an example:
['a', 'b', 'c'].forEach((data, i) => {
this[`id${i+1}`] = data
})
Would lead to this:
id1: a
id2: b
id3: c
For your specific code, assuming the object has an "id" column that should be used (which would still prefix the variable with "id"):
foodItems.forEach((data) => {
this[`id${data.id}`] = data
})
Assuming an object like
const foodItems = [{id: 'foo', value: 'bar'}], it would result in this:
idfoo: {id: 'foo', value: 'bar'}
If you can provide some more context, maybe we could come up with a better solution that actually helps you?

Using arrays to group properties together in a Javascript class rather than listing each one as it's own property

I'm brand new to javascript (2nd week of learning) so I'm sorry if this is a stupid question! I've found 2 ways to do the thing I'm trying to do and need some advice on whether the second way is acceptable.
I know a class can have properties that take arrays where the array lists multiple values of that one property. However, if I have a class with properties that are group-able (relate to the same aspect of the object) can I make them into one property that takes an array rather than listing each as a property?
So, if I have a Tent class with a mainUses property, I know I can pass a new instance an array for a tent that has multiple main uses.
class Tent {
constructor(mainUses){
this.mainUses = mainUses;}};
const myTent = new Tent (["Backpacking","Mountaineering","Bikepacking"]);
And if I also have a minimum pack weight, standard weight and maximum weight for the tent I can do:
class Tent {
constructor(mainUses,minWeight,standardWeight,maxWeight){
this.mainUses = mainUses;
this.minWeight = minWeight;
this.standardWeight = standardWeight;
this.maxWeight = maxWeight;}};
const myTent = new Tent (["Backpacking","Mountaineering","Bikepacking"], "2kg","2.2kg","2.4kg");
But what about if I group the 3 weights into one 'super-property' (for want of a better description) like this:
class Tent {
constructor(mainUses,weight){
this.mainUses = mainUses;
this.weight = weight;}};
And then pass the 'super-property' an array listing the 3 weights:
const myTent = new Tent (["Backpacking","Mountaineering","Bikepacking"],["2kg","2.2kg","2.4kg"]);
And then, so that they can still easily be accessed, add a comment to the class listing the indices to use when I make a new instance or want to access something.
/*minWeight [0], standardWeight [1], maxWeight[2]*/
So that myTent.minWeight would become myTent.weight[0].
Is there any reason I shouldn't do it this way? It appears to work for what I'm trying to do but I'm worried that it's bad form/hacky/wrong-for-some-other-reason to use it like this?
I've tried to search for an example of it being used this way but I don't really know how to describe it succinctly enough to search effectively. The example I've used doesn't show it well but where I have lots of properties that I could group into a single array, it ends up being much simpler. I feel like it's semantically...off somehow?
You could do it like this, but if you have different properties in the same array it would maybe be better to use an associative array. In my opinion, it would be better organized. It would also be more object oriented and it would still be ok if you add more properties.
const myTent = [
{ item: 'Backpacking',
weight: '2kg',
},
{ item: 'Mountaineering',
weight: '2.2kg',
},
{ item: 'Bikepacking',
weight: '2.4kg',
},
];
Objects are generally used instead of arrays for this purpose because it is much easier to not get confused about which element means which thing when they are named.
// Weight property
{
min: 2,
standard: 2.2,
max: 2.4,
unit: 'kg',
}

Multiple objects inside main object cannot be sorted by key value, but objects inside an array can be - how and why does this happen?

This is a follow up to a previous question I asked:
Sort JSON response by key value
So I know that objects cannot be sorted using the .sort method and if I push each object into an array, I can sort it the way I want.
Why does .sort not work on this:
{ A:{...}, B:{...}, C:{...} }
but works on this:
[ {...}, {...}, {...} ]
It's still accessing and working with object properties in both examples, right?
Here's some code:
var query = {
"736":{
ns: 42,
pageid: 12,
lang: "en",
index: 3
},
"421":{
ns: 12,
pageid: 36,
lang: "en",
index: 4
},
"102":{
ns: 2,
pageid: 19,
lang: "en",
index: 1
}
};
var queryArr = [{ns: 42, pageid: 12, lang: "en", index: 3}, {ns: 12, pageid: 36, lang: "en", index: 4}, {ns: 2, pageid: 19, lang: "en", index: 1}];
query is an object with multiple objects in it, and queryArr is an arry with multiple objects in it. If I wanted to sort query by its index key's value, I'd have to convert it to an arry first, and then run .sort on that array, correct?
What I want to know is why. What prevents query from being sorted, but allows the objects inside queryArr to be sorted? They're both still objects right? The only difference is the outer body is an object in the first, and an array in the second - but it's still working with objects when sorting.
My sort function still referneces the index using the object property accessor:
queryArr.sort(function(i,j){
return j.index - i.index;
});
Array object is object where the positive integer keys are used:
a = [, 1]
a[.1] = .1
a[-1] = -1
console.log( a )
console.log( { ...a } )
If the order of the properties can't be guaranteed, then for example array object [0, 1] can be stored as { "0": 0, "1": 1 } or { "1": 1, "0": 0 }.
Most array looping constructs will look for the "0" property before the "1" property, so the property order doesn't really matter.
Sorting array doesn't change it's properties order, but swaps the values associated with the properties.
Arrays are a special way of sequentially storing data. In the earliest implementations, this would be done by actually storing the array objects sequentially in memory. And resorting would actually physically move the objects in memory. So in your example where you have indices 102, 421, and 736. If you translated this to an array, you would actually have an array of length 737. 0 to 101 would be undefined, then you would have your object at 102. 103 to 420 would be undefined, then object 421. Et cetera.
Good to note that in your example when you translated your object into an array, you lost your keys (102, 421, 736). They simply became (0,1,2). In your example maybe this was okay, but if you had an object with properties like width, height, length, having these replaced with simple array indices like 0,1,2 would be a pretty significant loss of information.
Objects don't work the same way at all. They are not designed to store data sequentially, but hierarchically. So you can have a key 102 that points to an object, but you don't have to have keys 0-101. And key 102 doesn't designate the "order" of the item. It's just a name, and it could just as easily be length or fred or green as 102.
This mirrors reality. For example you might have an array to store a group of people, perhaps starting in order of age. And you could re-sort the list by different properties, like alphabetical by last name, or by height, etc.
But if we look at the objects within that array, it really makes no sense to talk about the order of firstName, lastName, height, weight, age, etc. There isn't really any "order" to speak of: weight doesn't have to come before height, or vice versa. And some people may like to see Last,First, while others prefer First Last. These properties are things we mostly want to be able to access directly by name, so an array isn't really ideal. We want named properties. Hence an object. Don't be confused just because you chose numbers as your property names...they're still names, not indices.
However it is of course possible to iterate all the properties of an object, and it is even possible to control the order in which you iterate them. Traditionally in javascript this iteration was done with the for...in syntax, which goes all the way back to es1. But you couldn't control the order in which the object's keys were iterated. To control order we would have to use for...in to populate an array of keys, then sort the array, then re-loop over the array.
However, it is possible in the newer es6 javascript world to iterate in some great new ways. For example, you can use Object.keys() to get an array of all the object keys (property names), and then you could sort this array. Saves the step of populating an array with for...in.
Another more advanced possibility in es6 (which uses Object.keys) is to actually make the object itself iterable by adding a Symbol.iterator. Again, this only works in es6+.
However the Symbol.iterator gives you a lot of power. This is what it looks like:
query[Symbol.iterator] = function*() {
let properties = Object.keys(this).sort();
for(let p of properties) {
yield {key:p, value:this[p]}
}
}
Once you add this iterator to the object, now you can use things like for...of. And in this example I added a .sort(), so this would iterate over the object's properties in ascending numeric order by key: 102, 421, 736. And since we are yielding an object with key and value, we are still able to see the key value, which we would NOT have if we had just translated to an array.
for(let {key,value} of query) {
console.log(key);
}

Few large arrays, or one large array of few variables?

apologies if this question has been asked before but I'm finding it hard to word the question in a way that might have been asked before.
Q: Is it more efficient to have something like:
mass[128] = {0.0}
speed[128] = {0.0}
age[128] = {0}
Or:
properties[128] = {mass=0.0, speed=0.0, age=0}
And why? Is there a simple rule to always bear in mind, (are few larger arrays better than many small etc)?
I'm writing in JS using Chrome. Reading and writing to elements very often.
Thanks very much!
In general, the answer here is: Do what makes the most sense to let you write the simplest, clearest code; and worry about any performance or memory issue if you actually run into one.
Using an array of objects with named properties will likely be more efficient in terms of access time on a modern JavaScript engine, and will likely be less efficient in terms of memory use. In both cases, the difference will be incredibly minor and probably imperceptible.
If your values are numbers and your arrays can be of fixed size, you might use typed arrays, since they really are arrays (where as normal arrays aren't1 unless the JavaScript engine can do it as an optimization). But there are downsides to typed arrays (their being fixed size, for instance), so again, if and when it becomes necessary...
Example of an array of objects with named properties:
var properties = [
{mass: 0, speed: 0, age: 0},
{mass: 1, speed: 1, age: 1},
// ...
];
If you're using ES2015 (you said you're using Chrome, so you can), you might make that a const:
const properties = [
{mass: 0, speed: 0, age: 0},
{mass: 1, speed: 1, age: 1},
// ...
];
That only makes properties a constant, not the contents of the array it points to, so you can still add, remove, or amend entries as desired.
1 That's a post on my anemic little blog.

An efficient way to get the difference between two arrays of objects?

I have two arrays of objects:
var a = [ {'id': 20}, {'id': 15}, {'id': 10}, {'id': 17}, {'id': 23} ];
var b = [ {'id': 90}, {'id': 15}, {'id': 17}, {'id': 23} ];
I'd like to get objects which are in a, but not in b. Results from this example would be:
{'id': 20} and {'id': 10}.
Because the arrays could be large, I need an efficient way to do this.
// Make hashtable of ids in B
var bIds = {}
b.forEach(function(obj){
bIds[obj.id] = obj;
});
// Return all elements in A, unless in B
return a.filter(function(obj){
return !(obj.id in bIds);
});
very minor addendum: If the lists are very large and you wish to avoid the factor of 2 extra memory, you could store the objects in a hashmap in the first place instead of using lists, assuming the ids are unique: a = {20:{etc:...}, 15:{etc:...}, 10:{etc:...}, 17:{etc:...}, 23:{etc:...}}. I'd personally do this. Alternatively: Secondly, javascript sorts lists in-place so it doesn't use more memory. e.g. a.sort((x,y)=>x.id-y.id) Sorting would be worse than the above because it's O(N log(N)). But if you had to sort it anyway, there is an O(N) algorithm that involves two sorted lists: namely, you consider both lists together, and repeatedly take the leftmost (smallest) element from the lists (that is examine, then increment a pointer/bookmark from the list you took). This is just like merge sort but with a little bit more care to find identical items... and maybe pesky to code. Thirdly, if the lists are legacy code and you want to convert it to a hashmap without memory overhead, you can also do so element-by-element by repeatedly popping the elements off of the lists and into hashmaps.
With lodash 4.12.0 you can use _.differenceBy.
_.differenceBy(a, b, 'id');
A general way to do this would be:
put all objects from b into a hashtable
iterate over a, for each item check if it is in the hashtable
A lot of programming environments have set and/or HashSet implementations these days, which make it very simple to do this.
In special cases, other ways might be more efficient. If, for example, your elements were byte-sized values, and a and b both fairly big, then I would use a boolean array "flags" with 256 elements, initialize all to false. Then, for each element x of b, set flags[x] to true. Then iterate over a, and for each y in a, check if flags[y] is set.
If you not adverse to including a library use underscore.js it has a good intersection function
http://documentcloud.github.com/underscore/

Categories

Resources