Arrays with Objects as Key Values in Javascript - javascript

I have the following requirement. I have a pair of integers which is to act as keys and another pair of integers which should act as values. That is:
obj[{key1:12,key2:23}]=[2,3];
obj[{key1:12,key2:22}]=[4,3];
obj[{key1:34,key2:12}]=[4,33];
Also finally when the population of this list is over, I would like to sequentially access the elements of the object/array.
Now it is my understanding that for such arrays which take an object as key, they are known as associative arrays and Javascript doesn't support them..
The following will be the operations I will perform on this structure :
Insertion: I will have keys like (2,3) or (2,4) which I would like to insert into the array with a new keyvalue pair such as [1,2],
Lookup : I may have a key pair like (2,3) which is already inserted into this array and I would like to get it back so that I can modify it.
That is something like:
if(obj[{key1:2,key2:3}])
obj[{key1:2,key2:3}]=[2,5];
else
obj[{key1:2,key2:3}]=[2,-1];
Any suggestions as to how I can implement this in Javascript?
EDIT: These are the two things I tried:
First I made it as an array of objects. This approach didn't work because from looking around, I knew that in such cases, Javascript will call the toString method to get the string equivalent of the object which it will then use an index.
Second, I tried to do an object with object keys containing sub-objects. Something along the lines of this answer: Answer. However I am not sure how to get sequential access to all the elements after I am done with the insertion phase.

You're probably not going to like this much, but it'll at least give you a stable key:
obj[JSON.stringify({key1:12,key2:23})]=[2,3];
So, the big problem is that in an object the 'key' (really, the 'property') must be a string, or be able to be stringified. In your examples, {key1:12,key2:23} will always be stringified to [object Object]. So you'll never get a unique key. The only way to get that unique key is to really serialize it, such as by using the JSON.stringify method.
Note that on IE8 I think you have to include a JSON class.

Here is an object oriented way to do it:
// Constructor
function AssociativeArray() {
this.length = 0;
}
// Add or set value
AssociativeArray.prototype.set = function(key, value) {
key = key.key1+'|'+key.key2;
if(!this[key]) {
this.length++;
}
this[key] = value;
};
// Lookup
AssociativeArray.prototype.get = function(key) {
return this[key.key1+'|'+key.key2];
};
AssociativeArray.prototype.toString = function() {
var k, arr = [];
for(k in this) {
if(this.hasOwnProperty(k) && k !== 'length') {
arr.push(this[k]);
}
}
return arr;
};
// Create Associative Array
var arr = new AssociativeArray();
// empty array
console.log(arr.toString(), 'length='+arr.length); // [] length=0
// add value
arr.set({key1:1, key2:2}, [1,1]);
console.log(arr.toString(), 'length='+arr.length); // [[1,1]] length=1
// add value
arr.set({key1:2, key2:1}, [2,2]);
console.log(arr.toString(), 'length='+arr.length); // [[1,1], [2,2]] length=2
// set value
arr.set({key1:2, key2:1}, [3,3]);
console.log(arr.toString(), 'length='+arr.length); // [[1,1], [3,3]] length=2
// lookup and set
if(arr.get({key1:2, key2:3})) {
arr.set({key1:2, key2:3}, [2,5]);
} else {
arr.set({key1:2, key2:3}, [2,-1]);
}
console.log(arr.toString(), 'length='+arr.length); // [[1, 1], [3, 3], [2, -1]] length=3
Fiddle here: http://jsbin.com/ohOwala/3/edit

You could use a bidimensional array
var arr = [];
arr[2] = [];
arr[2][3] = [1, 2];
Or you could use an object and access the pairs using the object properties names
obj = {
_2_3: [1, 2],
_2_1: [4, 1],
_1_2: [3, 2]
};
and access them like this obj["_2_3"] or this obj._2_3
or maybe you could nest em
obj = {
_1: {
_2: [2,1]
}
};
so you could access them like this obj["_1"]["_2"]
or maybe this
obj = {
1: {
2: [2,1]
}
};
But you will be forced to use associatve array notation obj["1"]["2"]
and as far as i know using the associative array like way for accessing objects properties isnt a good practice

I asked where the objects {key1:2,key3:2} came from because if you have control over it you can implement a toString method for those types that will take care of the Object to string conversion so it can be used as a property name.
//define keypair object type
var MyKeyPair = function(key1,key2){
this.key1=key1;
this.key2=key2;
};
//define tostring for this type
// later obj[aKeyPairInstance] will
// invoke the toString method
// if you don't do this then [Object object]
// would be returned for toString
MyKeyPair.prototype.toString=function(){
//since you know there is only going to be key1 and key2
// you could just:
// return this.key1+":"+this.key2;
//Here follows a more general approach but it'll cost
// you more cpu time, if working with very large amounts
// of data use the shorter version.
var ret=[];
for(thing in this){
if(this.hasOwnProperty(thing)){
ret.push(thing);
ret.push(":");
ret.push(this[thing]);
ret.push(",");
}
}
return ret.join("");
};
// make a bunch of keyPair objects
var keys = [
new MyKeyPair(21,33),
new MyKeyPair(22,34),
new MyKeyPair(23,35),
new MyKeyPair(24,36)
];
//create an object and give it properties
// based on the tostring value of the keypairs
var obj={};
for(var i = 0,len=keys.length;i<len;i++){
obj[keys[i]]=[keys[i].key1,keys[i].key2];
};
console.log(obj);//<=this would not log any usefull info in IE
//Use Chrome, Firefox, Opera or any other browser instead

Related

How to do a basic javascript loop / accessing array data

I have been searching A LOT to find a simple way to loop through an array (I haven't used javascript much) and I just can't seem to make sense of the examples I've seen.
I also want to retrieve data from an array...
The following example I can understand:
https://www.w3schools.com/js/js_loop_for.asp
But it's just not useful for the use case I want it for.
Say I have an array that looks like this:
array1 = [{'key':1, 'values':["one", "1"]}, {'key':2, 'values':["two", "2"]}]
Question 1: How can I access the first object in that array, i.e. where the 'key' = 1?
Question 2: How can I then loop through the "values" from this object?
e.g. In Python I would do something like:
get_first_object = array1[0]
for value in array1['values']:
print value
How can I do this kind of coding in javascript?
Edit
I didn't mention this properly
My "array1" is coming from a Python view and so the output of this is different to a standard JS array (see output of console.log below):
["[{'key': 1, 'values': ["one", "1"]}, {'key': 2, 'values':["two", "2"]}]"]
so when I do var object = array1[0] I get the following output:
[{'key': 1, 'values': ["one", "1"]}, {'key': 2, 'values': ["two", "2"]}]
It doesn't seem to be getting the first object but rather seeing the whole thing as one object.
Also
I require to get this dynamically - so I can't actually hard code "array1[0]" or "array1[1]" - How can I do this?
How I am defining the array
var array1 = ["{{ my_array_1|safe }}"];
Edit 2
The way I wish to get the object from the array is like so:
var selected_id = 1;
var selected_object = array[key=selected_id];
Let's assume that your array is this:
var array = [{'key': 1, 'values': ["one", "1"]}, {'key': 2, 'values': ["two", "2"]}];
This is an array which contains javascript objects, each with 2 properties, 'key', whose corresponding value is an integer and 'values' whose corresponding value is an array of data. If I understand this correctly, you want, given an integer input_id, to access the aforementioned array of data.
function access_data (id) {
for(let obj of array){
if(obj['key'] == id){
return obj['values'];
}
}
}
If you are familiar with python you probably recognize the for .... of syntax, since it's basically the same as python's for .... in. The above code assumes that your array is a global variable called array. Calling the function with an integer argument loops through every object your array contains, checks if its 'key' property matches the given id, and if it does, the corresponding array of data is returned.
More details on for ... of loops here
This self explanatory code should rectify your doubts
var array1 = [{'key':1, 'values':["one", "1"]}, {'key':2, 'values':["two", "2"]}];
// First Object
var firstObject = array1[0];
console.log("First object", firstObject);
// Accessing key property of first object
var keyOfFirstObj = firstObject.key;
console.log("Key", keyOfFirstObj);
// Iterating through all the values of first object
Object.values(firstObject).forEach(
el => console.log("Value -- ", el)
)
You can hardcode it: array1[0].key // 1
Use forEach to loop over:
const array1 = [{'key':1, 'values':["one", "1"]}, {'key':2, 'values':["two", "2"]}]
array1.forEach(arrItem => console.log(arrItem))
Or map over it if you intend to change datas as #str said below:
const array1 = [{'key':1, 'values':["one", "1"]}, {'key':2, 'values':["two", "2"]}]
array1.map(arrayItem => console.log(arrayItem);
On mapvs forEach:
https://codeburst.io/javascript-map-vs-foreach-f38111822c0f
There are a few ways to do this, the basic for loop and the for..of loop
for
for (let i = 0; i < array1.length; i++) {
console.log(array1[i])
}
for..of
for (const val of array1) {
console.log(val)
}
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/for...of
if you want to select an object that has a key property of "1", you could loop through the array using the methods above, returung when that condition is true, or you could use Array#filter
const filtered = array1.filter(item => item['key'] === 1) //=> returns a new array
const myObj = filtered[0]
If you want a similar syntax to Python, you Coups use the for...in loop:
let get_first_object = array1[0];
for (let index in array1['values']){
console.log(array1['values'][index]);
}
Edit:
As for your edit, you need 2 loops
let objectArray= array1[0];
if(objectArray){
for(let outerIndex in objectArray){
for(let innerIndex in objectArray[outerIndex]['values']){
console.log(objectArray[outerIndex]['values'][innerIndex];
}
}
}
Edit:
let objectArray= array1[0];
if(objectArray){
let valuesObject=objectArray.filter(f=>f.key===selectedId);
for(let innerIndex in valuesObject['values']){
console.log(valuesObject ['values'][innerIndex];
}
}
}

Named objects and collection of them

not sure how to ask tbh :)
I'm used of PHP's associative arrays so much that I struggle to understand how to create an "named array" of objects.
Example:
I have two arrays, two ints and one boolean. This represents one of my entities. I have multiple entities on which I'm doing some work.
In PHP I would write:
$entitites[$entitity_id]['items'][] = $item;
$entitites[$entitity_id]['items_status'][] = $item_status;
$entitites[$entitity_id]['items_count']++;
and so on..
How do I do this with objects in JS?
var entities = {items:[], items_status: [], items_count: 0};
entities[entity_id].items.push(item)
How does one name his object for later access (via name or in my case, entity_id?)
This code doesnt work for me to this extend that my webpage goes blank without any errors produced :S
I also tried this:
var entities = {};
var entity = {items:[], items_status: [], items_count: 0};
but then I dont know how to always add values to already existing object in entities object and how to call that exact object via name eg. entity_id.
Halp :(
Keep entities as an object. Then you can just go ahead and add each entity_id as a key and an object which has all the details of that entity as the value.
var entities = {};
entities["1234"] = {
"items" : [],
"items_status" : [],
"items_count" : 0
};
There are 2 types involved here: Objects & Arrays.
Arrays are simple and you're probably familiar with them from any other language:
var myArray = []; // this is an empty array
myArray[0] = 1;
myArray[1] = 2;
myArray[2] = 3;
// you could also use "var myArray = [1, 2, 3];" instead
alert(myArray[1]); // alerts the value 2
Note: arrays are actually objects, and can have non-index properties as well
You can also use various array functions such as .push(), .pop(), .shift() and so on to mutate the array instead.
Objects share the square brackets notation, but the purpose is different:
var myObject = {}; // this is an empty object
myObject[0] = 1;
myObject[1] = 2;
myObject[2] = 3;
alert(myObject[1]); // alerts the value 2
// but also...
myObject['prop'] = 4;
alert(myObject['prop']); // alerts the value 4
// and
myObject.prop2 = 5;
alert(myObject.prop2); // alerts the value 5
// and lastly
alert(myObject.prop); // alerts the value 4
So while arrays are accessed by index, objects are accessed by property names.
As for your entities, it looks like an array of objects. Lets see how we can do that:
function Entity() {
this.items = [];
this.items_status = [];
this.items_count = 0;
}
var entitites = [];
entities.push(new Entity());
entities[0].items = [1, 2, 3];
entities[0].items_status = ['good', 'good', 'poor'];
entities[0].items_count = 3;
Or you can wrap insertion in a more elegant function:
Entity.prototype.insert(item, status) {
this.items.push(item);
this.items_status.push(status);
this.items_count++;
}
entities[0].insert(4, 'excellent!');
If you want to keep control of the indexes in your JS array you can do so by not using .push() :
var entities = [];
entities[5] = {items:[], items_status:[], items_count:0};
Just replace 5 by your integer entity_id variable, and there you go.
You can use a regular javascript object to create the associative array you're looking for.
Actually it's PHP's implementation that's abit off but all they do is call it different (associative array) to most other language that simply refer to it as an object or hash.
You can use numeric keys in JS and still access them with the [] square brackets.
It works like this:
var my_obj = {};
my_obj[5] = 'any value';
console.log(my_obj); // {5: 'any value'}
JS will not add any redundant undefined to missing indexes either so when looping over the collection you won't loop over undefined.
Also, I can access the object by using the key as a string or as number so you won't have to check if the key is the right type. Taken from the above example:
console.log(my_obj['5']); // 'any value'
console.log(my_obj[5]); // 'any value'
JS Objects are the equivelant of PHP assoc arrays except JS objects are much more flexible than PHP's associative arrays.
The only downside to this is that you can't have duplicate keys.
No two keys may exist that share the same name, in an array if you .push(an_item) it will create a new index making even a duplicate data entry unique but when overwriting a key with a new value only the last value will persist, mind that :)

Sort javascript key/value pairs inside object

I have some problem with sorting items inside object. So I have something like this:
var someObject = {
'type1': 'abc',
'type2': 'gty',
'type3': 'qwe',
'type4': 'bbvdd',
'type5': 'zxczvdf'
};
I want to sort someObject by value, and this is where I have problem.
I have sorting function that should return key/value pairs sorted by value:
function SortObject(passedObject) {
var values = [];
var sorted_obj = {};
for (var key in passedObject) {
if (passedObject.hasOwnProperty(key)) {
values.push(passedObject[key]);
}
}
// sort keys
values.sort();
// create new object based on Sorted Keys
jQuery.each(values, function (i, value) {
var key = GetKey(passedObject, value);
sorted_obj[key] = value;
});
return sorted_obj;
}
and function to get key:
function GetKey(someObject, value) {
for (var key in someObject) {
if (someObject[key] === value) {
return key;
}
}
}
The problem is in last part when creating new, returning object - it's sorted by key again. Why? And this is specific situation when i have to operate on object NOT on array (yes I know that would be easier...)
Does anyone know how to sort items in object?
Plain objects don't have order at all. Arrays -that are a special types of objects- have.
The most close thing that you can have is an array with the object values sorted . Something like, for example:
_valuesOfAnObjectSorted = Object.keys(object).map(function(k){ return object[k]; }).sort();
You have two possibilities:
Refactor your object into an array
Something like this:
var myObj = [
['type1', 'abc'],
['type2', 'gty'],
...
];
Or even better, since using it somewhere would not rely on array positions but full named keys:
var myObj = [
{name: 'type1', val:'abc'},
{name: 'type2', val:'gty'},
...
];
Use your object with an auxiliar array
Wherever you want to use your object ordered by the keys, you can extract the keys as an array, order it and traverse it to access the object
var ordKeys = Object.keys(myObj).sort(); // pass inside a function if you want specific order
var key;
for (var i = 0, len = ordKeys.length; i < len; i +=1) {
key = ordKeys[i]
alert(key + " - " + myObj[key]);
}
Combination of both of them
If the object is not constructed by you, but comes from somewhere else, you can use the second option approach to construct an array of objects as in the first option. That would let you use your array anywhere with perfect order.
EDIT
You might want to check the library underscore.js. There you have extremely useful methods that could do the trick pretty easily. Probably the method _.pairs with some mapping would do all the work in one statement.

JavaScript foreach loop on an associative array object

Why is my for for-each loop not iterating over my JavaScript associative array object?
// Defining an array
var array = [];
// Assigning values to corresponding keys
array["Main"] = "Main page";
array["Guide"] = "Guide page";
array["Articles"] = "Articles page";
array["Forum"] = "Forum board";
// Expected: loop over every item,
// yet it logs only "last" assigned value - "Forum"
for (var i = 0; i < array.length; i++) {
console.log(array[i]);
}
jQuery each() could be helpful: https://api.jquery.com/jQuery.each/
The .length property only tracks properties with numeric indexes (keys). You're using strings for keys.
You can do this:
var arr_jq_TabContents = {}; // no need for an array
arr_jq_TabContents["Main"] = jq_TabContents_Main;
arr_jq_TabContents["Guide"] = jq_TabContents_Guide;
arr_jq_TabContents["Articles"] = jq_TabContents_Articles;
arr_jq_TabContents["Forum"] = jq_TabContents_Forum;
for (var key in arr_jq_TabContents) {
console.log(arr_jq_TabContents[key]);
}
To be safe, it's a good idea in loops like that to make sure that none of the properties are unexpected results of inheritance:
for (var key in arr_jq_TabContents) {
if (arr_jq_TabContents.hasOwnProperty(key))
console.log(arr_jq_TabContents[key]);
}
edit — it's probably a good idea now to note that the Object.keys() function is available on modern browsers and in Node etc. That function returns the "own" keys of an object, as an array:
Object.keys(arr_jq_TabContents).forEach(function(key, index) {
console.log(this[key]);
}, arr_jq_TabContents);
The callback function passed to .forEach() is called with each key and the key's index in the array returned by Object.keys(). It's also passed the array through which the function is iterating, but that array is not really useful to us; we need the original object. That can be accessed directly by name, but (in my opinion) it's a little nicer to pass it explicitly, which is done by passing a second argument to .forEach() — the original object — which will be bound as this inside the callback. (Just saw that this was noted in a comment below.)
This is very simple approach. The advantage is you can get keys as well:
for (var key in array) {
var value = array[key];
console.log(key, value);
}
For ES6:
array.forEach(value => {
console.log(value)
})
For ES6 (if you want the value, index and the array itself):
array.forEach((value, index, self) => {
console.log(value, index, self)
})
If Node.js or the browser support Object.entries(), it can be used as an alternative to using Object.keys() (Pointy's answer).
const h = {
a: 1,
b: 2
};
Object.entries(h).forEach(([key, value]) => console.log(value));
// logs 1, 2
In this example, forEach uses destructuring assignment of an array.
There are some straightforward examples already, but I notice from how you've worded your question that you probably come from a PHP background, and you're expecting JavaScript to work the same way -- it does not. A PHP array is very different from a JavaScript Array.
In PHP, an associative array can do most of what a numerically-indexed array can (the array_* functions work, you can count() it, etc.). You simply create an array and start assigning to string indexes instead of numeric.
In JavaScript, everything is an object (except for primitives: string, numeric, boolean), and arrays are a certain implementation that lets you have numeric indexes. Anything pushed to an array will affect its length, and can be iterated over using Array methods (map, forEach, reduce, filter, find, etc.) However, because everything is an object, you're always free to simply assign properties, because that's something you do to any object. Square-bracket notation is simply another way to access a property, so in your case:
array['Main'] = 'Main Page';
is actually equivalent to:
array.Main = 'Main Page';
From your description, my guess is that you want an 'associative array', but for JavaScript, this is a simple case of using an object as a hashmap. Also, I know it's an example, but avoid non-meaningful names that only describe the variable type (e.g. array), and name based on what it should contain (e.g. pages). Simple objects don't have many good direct ways to iterate, so often we'll turn then into arrays first using Object methods (Object.keys in this case -- there's also entries and values being added to some browsers right now) which we can loop.
// Assigning values to corresponding keys
const pages = {
Main: 'Main page',
Guide: 'Guide page',
Articles: 'Articles page',
Forum: 'Forum board',
};
Object.keys(pages).forEach((page) => console.log(page));
arr_jq_TabContents[key] sees the array as an 0-index form.
Here is a simple way to use an associative array as a generic Object type:
Object.prototype.forEach = function(cb){
if(this instanceof Array) return this.forEach(cb);
let self = this;
Object.getOwnPropertyNames(this).forEach(
(k)=>{ cb.call(self, self[k], k); }
);
};
Object({a:1,b:2,c:3}).forEach((value, key)=>{
console.log(`key/value pair: ${key}/${value}`);
});
This is (essentially) incorrect in most cases:
var array = [];
array["Main"] = "Main page";
That creates a non-element property on the array with the name Main. Although arrays are objects, normally you don't want to create non-element properties on them.
If you want to index into array by those names, typically you'd use a Map or a plain object, not an array.
With a Map (ES2015+), which I'll call map because I'm creative:
let map = new Map();
map.set("Main", "Main page");
you then iterate it using the iterators from its values, keys, or entries methods, for instance:
for (const value of map.values()) {
// Here, `value` will be `"Main page"`, etc.
}
Using a plain object, which I'll creatively call obj:
let obj = Object.create(null); // Creates an object with no prototype
obj.Main = "Main page"; // Or: `obj["Main"] = "Main page";`
you'd then iterate its contents using Object.keys, Object.values, or Object.entries, for instance:
for (const value of Object.values(proches_X)) {
// Here, `value` will be `"Main page"`, etc.
}
var obj = {
no: ["no", 32],
nt: ["no", 32],
nf: ["no", 32, 90]
};
count = -1; // Which must be a static value
for (i in obj) {
count++;
if (obj.hasOwnProperty(i)) {
console.log(obj[i][count])
};
};
In this code I used the brackets method for call values in an array because it contained an array. However, briefly the idea which a variable i has a key of property and with a loop called both values of the associative array.
It is the perfect method.
You can do this:
var array = [];
// Assigning values to corresponding keys
array[0] = "Main page";
array[1] = "Guide page";
array[2] = "Articles page";
array[3] = "Forum board";
array.forEach(value => {
console.log(value)
})
It seems like almost every answer is not what was asked at the very first place.
It's seems bit off that foreach-loop does not work. and simple for-loop will not work as well because length property will be zero in case of associative arrays(one of the fallback). but for-in do the thing for associative array
// Defining an array
var array = [];
// Assigning values to corresponding keys
array["Main"] = "Main page";
array["Guide"] = "Guide page";
array["Articles"] = "Articles page";
array["Forum"] = "Forum board";
// Expected: loop over every item,
// yet it logs only "last" assigned value - "Forum"
for (var index in array) {
console.log(index,array[index]);
}

Getting Length of Object in Javascript / jQuery

I am trying to set up an array in jQuery and I then need to do a for loop on it. But it seems that I cant use an associative array for some reason?
var items = new Array();
items['foo'] = 123456;
items['bar'] = 789012;
items['baz'] = 345678;
items['bat'] = 901234;
alert(items.length);
This is just a test, but it return 0?
You can't make associative array in JavaScript like what you want, instead you can use Object.
For example:
var items = {
foo : 123456,
bar : 789012,
baz : 345678,
bat : 901234
}
And to calculate the length you can do:
var getObjectSize = function(obj) {
var len = 0, key;
for (key in obj) {
if (obj.hasOwnProperty(key)) len++;
}
return len;
};
Use: getObjectSize(items); // output: 4
For more see here.
Another one is:
Object.keys(items).length;
But not supported by all browsers.
var items = new Array();
items['foo'] = 123456;
The problem lies in the very first line. You believe that you are adding an item to the array at the index foo, but you are actually adding a property to the items variable with a key foo and value 123456. If you were to type items.foo it would give you back your 123456.
The problem with this approach is that adding a property to an array does not magically increase it's length.
If you want to have non-numeric indexes, you need to use an object instead of an array:
var items = {
foo: 123456,
bar: 789012,
baz: 345678,
bat: 901234
};
Another approach might be to set up two different arrays, which you construct in parallel:
var items = [], items2 = [];
items.push('foo');
items2.push(123456);
// etc.
alert(items2.length);​
The efficiency of this approach depends on how you'll use it. If you're only going to loop through the list of items and do something to each of them, this approach may be more efficient. But if you need to use it like an associative array (items['foo']), then you're better off building an object.
The .length property returns the highest numerical index of the array. Thus, in your case, there is no numerical index and it returns 0. Try
items[98] = "something";
items.length will be 98..! Use the .length property with caution, and if you also want to count the non-numerical indici, loop over the Object (an Array is also an Object) and count its ownProperties.

Categories

Resources