Javascript object that maps keys to value & allows iteration over keys - javascript

I need to create object in javascript that allows to fetch values using keys & also iterate over keys. The primary requirement is fetching value by key but iteration is required to maintain sort order of entries by values(integer).
How do I go about creating such an object ?

sampleJson={
"1":"john",
"2":"johny"
}
You can iterate using for in loop
for(key in sampleJson){
//ur code
}

All objects in JavaScript are JSONeable! (is that really a word).
All objects in JavaScript are a collection of key value mappings.
A for in loop iterates over the keys of an object.

Native objects don't support exactly what you're looking for, but it's fairly straightforward to create a wrapper around native objects that provides extra functionality.
A possible approach:
function KeySortArr(obj) {
this.obj = obj || {};
}
KeySortArr.prototype = {
get: function(key) {
return this.obj[key];
},
set: function(key, value) {
this.obj[key] = value;
},
keys: function() {
var keys = [];
for(var i in this.obj) {
if (this.obj.hasOwnProperty(i))
keys.push(i);
}
return keys;
},
getKeysSortedByValue: function() {
var obj = this.obj;
return this.keys().sort(function(a, b) {
return obj[a] > obj[b];
});
}
};
Usage:
var arr = new KeySortArr();
arr.set("test", 4);
arr.set("another", 2);
arr.set("ok", 60);
arr.set("last", 14);
The following then:
arr.getKeysSortedByValue();
Returns:
["another, "test", "last", "ok"]
In other words, the keys are sorted by their associated value. This might not be exactly what you were looking for, but it should be close.

Related

How to access a String key in a javascript array of objects?

For example, the array is:
chipsArray = [{'cheetos':'good'},{'dorritos':'better'}]
Here, chipsArray[0] would give me {'cheetos':'good'}. Let's say I populated this array like the following:
chipsArray.push({[chips]:quality})
But now that I'm trying to access the cheetos or dorritos keys in each of objects in this array, I can't. Doing chipsArray[0].chips gives me undefined.
As far as I know when populating the key of an object with a certain value/variable, they should be wrapped in square braces. But how can we extract values from them later on when each of these objects are array indices like the example given above? I tried using Object.keys(chipsArray[index]), but this only gives me the keys whereas I'm trying to extract the specific value for that specific key.
Tl;Dr: How to extract the key of an object inside an array when the keys are strings like this:
chipsArray = [{'cheetos':'good'},{'dorritos':'better'}]
You could use Object.keys and get only the first element.
var chipsArray = [{ cheetos: 'good' }, { dorritos: 'better' }];
chipsArray.forEach(function (object) {
var key = Object.keys(object)[0];
console.log(key, object[key]);
});
Or create an object with the reference to the single objects
var chipsArray = [{ cheetos: 'good' }, { dorritos: 'better' }],
hash = Object.create(null);
chipsArray.forEach(function (object) {
hash[Object.keys(object)[0]] = object;
});
console.log(hash['dorritos']['dorritos']);
Use the following function. It returns the value by key in the array
function getItemByKey (key, array) {
var value;
array.some(function (obj) {
if (obj[key]) {
value = obj[key];
return true;
}
return false;
});
return value;
}
More about Array.prototype.some here
I think the easiest way is to access the value:
Object.values(chipsArray[i])
where i is the index of the array.
Output:
> chipsArray = [{'cheetos':'good'},{'dorritos':'better'}]
[ { cheetos: 'good' }, { dorritos: 'better' } ]
> Object.values(chipsArray[0])
[ 'good' ]

How do you search object for a property within property?

I have this object:
key = {
spawn:{type:1,img:app.assets.get('assets/spawn.svg')},
wall:{type:2,img:app.assets.get('assets/wall.svg')},
grass:{type:3,img:app.assets.get('assets/grass.svg')},
spike:{type:4,img:app.assets.get('assets/spike.svg')},
ground:{type:5,img:app.assets.get('assets/ground.svg')}
};
And I have an array with only types and I need to add the given image to it, the array looks something like this:
[{type:1,image:null},{type:3,image:null},{type:2,image:null},{type:2,image:null},{type:5,image:null}]
Basically I want to loop the array, find the type in the key object and get the given image and save it into the array.
Is there any simple way to do this?
One thing that stands out here for me is the line
...get the given image and save it into the array
I'm assuming this means the original array. I think a better approach would be to map the appropriate keys and values to a new array but I've assumed, for this example, that it's a requirement.
In an attempt to keep the solution as terse as possible and the request for a lodash solution:
_.each(key, function(prop){
_.each(_.filter(types, { type: prop.type }), function(type) { type.image = prop.img });
});
Given the object of keys and an array of objects like so:
var key = {
spawn:{type:1,img:app.assets.get('assets/spawn.svg')},
wall:{type:2,img:app.assets.get('assets/wall.svg')},
grass:{type:3,img:app.assets.get('assets/grass.svg')},
spike:{type:4,img:app.assets.get('assets/spike.svg')},
ground:{type:5,img:app.assets.get('assets/ground.svg')}
};
var arr = [{type:1,image:null},{type:3,image:null},{type:2,image:null},{type:2,image:null},{type:5,image:null}];
We can first create an array of the properties in the object key to make iterating it simpler.
Then loop over the array arr, and upon each member, check with a some loop which image belongs to the member by its type (some returning on the first true and ending the loop).
You can change the forEach to a map (and assign the returned new array to arr or a new variable) if you want the loop to be without side-effects, and not to mutate the original array.
var keyTypes = Object.keys(key);
arr.forEach(function (item) {
keyTypes.some(function (keyType) {
if (key[keyType].type === item.type) {
item.image = key[keyType].img;
return true;
}
return false;
});
});
The smarter thing would be to change the object of the imagetypes so that you could use the type as the accessing property, or create another object for that (as pointed out in another answer).
I'm not sure if this solution is modern, but it does not use any loops or recursion.
object = {
spawn: {type:1, img:app.assets.get('assets/spawn.svg')},
wall: {type:2, img:app.assets.get('assets/wall.svg')},
grass: {type:3, img:app.assets.get('assets/grass.svg')},
spike: {type:4, img:app.assets.get('assets/spike.svg')},
ground: {type:5, img:app.assets.get('assets/ground.svg')}
};
arr = [
{type:1, image:null},
{type:3, image:null},
{type:2, image:null},
{type:2, image:null},
{type:5, image:null}
];
var typeImages = {};
Object.getOwnPropertyNames(object).forEach(function(value){
typeImages[object[value].type] = object[value].img;
});
arr = arr.map(function(value){
return {
type: value.type,
image: typeImages[value.type]
};
});
var key = {
spawn:{type:1,img:app.assets.get('assets/spawn.svg')},
wall:{type:2,img:app.assets.get('assets/wall.svg')},
grass:{type:3,img:app.assets.get('assets/grass.svg')},
spike:{type:4,img:app.assets.get('assets/spike.svg')},
ground:{type:5,img:app.assets.get('assets/ground.svg')}
};
var typesArray = [{type:1,image:null},{type:3,image:null},{type:2,image:null},{type:2,image:null},{type:5,image:null}];
for(var i = 0, j = typesArray.length; i < j; i++)
{
typesArray[i].image = getKeyObjectFromType(typesArray[i].type).img;
}
function getKeyObjectFromType(type)
{
for(var k in key)
{
if(key[k].type == type)
{
return key[k];
}
}
return {};
}
for (var i = 0; i < typesArray.length; i++) {
for (prop in key) {
if (key[prop].type === typesArray[i].type) {
typesArray[i].image = key[prop].img;
}
}
}
It loops through the array ("typesArray"), and for each array item, it go through all the objects in key looking for the one with the same "type". When it finds it, it takes that key object's "img" and saves into the array.
Using lodash (https://lodash.com/):
var key = {
spawn:{type:1,img:app.assets.get('assets/spawn.svg')},
wall:{type:2,img:app.assets.get('assets/wall.svg')},
grass:{type:3,img:app.assets.get('assets/grass.svg')},
spike:{type:4,img:app.assets.get('assets/spike.svg')},
ground:{type:5,img:app.assets.get('assets/ground.svg')}
};
var initialList = [{type:1,image:null},{type:3,image:null},{type:2,image:null},{type:2,image:null},{type:5,image:null}];
var updatedList = _.transform(initialList, function(result, item) {
item.image = _.find(key, _.matchesProperty('type', item.type)).img;
result.push(item);
});
This will go over every item in the initialList, find the object that matched their type property in key and put it in the image property.
The end result will be in updatedList

Getting all the values for a given key, in an array of objects, using JavaScript and/or D3.js

I'm building a dashboard that uses D3.js for charts. I have a large array of objects. Each object has 32 key value pairs, with the same keys. Doesn't anyone know a good way to get all the values for a given key?
EDIT:
As soon as I asked the question a simple function came to me. Also thought maybe a function already existed that I wasn't finding.
function getValues(data, key){
var values = [];
data.forEach(function(d){
var v = d[key];
if(!d3.set(values).has(v)){
values.push(v);
}
})
return values;
}
If you're already using d3, take a look at Mike Bostock's "Underscore Equivalents" gist: https://gist.github.com/mbostock/3934356
So
data.map(function(d) { return d[key]; });
will get you all the values. If you only want unique values, use
d3.set(data.map(function(d) { return d[key]; })).values());
I have to create a lot of dashboards using D3 as well. Another option for you which I utilize a lot is underscore.js. It saves me time, and for my needs helps condense code. There is a function called 'pluck' in underscore, which does exactly what you asked for. For an array of objects, you can declare a key and it will return all values.
Example:
var data = [{name: 'dan', value: 40}, {name: 'ryan', value: 50}];
var getKeys = _.pluck(data, 'name');
=> ["dan", "ryan"]
http://underscorejs.org/#pluck
Use d3.keys():
d3.keys(data).filter(function(key) { return key })
Assuming you mean values as simple primitive values -
You can use this altered code of myne (which was originally used to flatten object actually) - to find all the values for specific key (recursive) :
Example : for a very complex object , let's find all the values for a given key named "a"
var data ={a:5,g: [{"a":1,"b":[4,5,6,{a:55},[33, new Date()]]},{"c":2},{"a":3}]};
var g=[];
if (!Object.keys) { //not all browsers support it
Object.keys = function (obj) {
var keys = [],
k;
for (k in obj) {
if (Object.prototype.hasOwnProperty.call(obj, k)) {
keys.push(k);
}
}
return keys;
};
}
function actualType(o)
{
return Object.prototype.toString.apply(o);
}
var arr=actualType([]);
var obj=actualType({});
function work(a, val)
{
if (actualType(a) == obj || actualType(a) == arr)
{
for (var j = 0; j < Object.keys(a).length; j++)
{
if (Object.keys(a)[j] == val) g.push(a[Object.keys(a)[j]]);
else
work(a[Object.keys(a)[j]], val);
}
}
}
work(data,'a') //'a' is the value we're searching
console.log(g) //[5, 1, 55, 3]
http://jsbin.com/yofafove/1/edit

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 data structure for fast lookup and ordered looping?

is there a data structure or a pattern in Javascript that can be used for both fast lookup (by key, as with associative arrays) and for ordered looping?
Right, now I am using object literals to store my data but I just disovered that Chrome does not maintain the order when looping over the property names.
Is there a common way to solve this in Javascript?
Thanks for any hints.
Create a data structure yourselves. Store the ordering in an array that is internal to the structure. Store the objects mapped by a key in a regular object. Let's call it OrderedMap which will have a map, an array, and four basic methods.
OrderedMap
map
_array
set(key, value)
get(key)
remove(key)
forEach(fn)
function OrderedMap() {
this.map = {};
this._array = [];
}
When inserting an element, add it to the array at the desired position as well as to the object. Insertion by index or at the end is in O(1).
OrderedMap.prototype.set = function(key, value) {
// key already exists, replace value
if(key in this.map) {
this.map[key] = value;
}
// insert new key and value
else {
this._array.push(key);
this.map[key] = value;
}
};
When deleting an object, remove it from the array and the object. If deleting by a key or a value, complexity is O(n) since you will need to traverse the internal array that maintains ordering. When deleting by index, complexity is O(1) since you have direct access to the value in both the array and the object.
OrderedMap.prototype.remove = function(key) {
var index = this._array.indexOf(key);
if(index == -1) {
throw new Error('key does not exist');
}
this._array.splice(index, 1);
delete this.map[key];
};
Lookups will be in O(1). Retrieve the value by key from the associative array (object).
OrderedMap.prototype.get = function(key) {
return this.map[key];
};
Traversal will be ordered and can use either of the approaches. When ordered traversal is required, create an array with the objects (values only) and return it. Being an array, it would not support keyed access. The other option is to ask the client to provide a callback function that should be applied to each object in the array.
OrderedMap.prototype.forEach = function(f) {
var key, value;
for(var i = 0; i < this._array.length; i++) {
key = this._array[i];
value = this.map[key];
f(key, value);
}
};
See Google's implementation of a LinkedMap from the Closure Library for documentation and source for such a class.
The only instance in which Chrome doesn't maintain the order of keys in an object literal seems to be if the keys are numeric.
var properties = ["damsonplum", "9", "banana", "1", "apple", "cherry", "342"];
var objLiteral = {
damsonplum: new Date(),
"9": "nine",
banana: [1,2,3],
"1": "one",
apple: /.*/,
cherry: {a: 3, b: true},
"342": "three hundred forty-two"
}
function load() {
var literalKeyOrder = [];
for (var key in objLiteral) {
literalKeyOrder.push(key);
}
var incremental = {};
for (var i = 0, prop; prop = properties[i]; i++) {
incremental[prop] = objLiteral[prop];
}
var incrementalKeyOrder = [];
for (var key in incremental) {
incrementalKeyOrder.push(key);
}
alert("Expected order: " + properties.join() +
"\nKey order (literal): " + literalKeyOrder.join() +
"\nKey order (incremental): " + incrementalKeyOrder.join());
}
In Chrome, the above produces: "1,9,342,damsonplum,banana,apple,cherry".
In other browsers, it produces "damsonplum,9,banana,1,apple,cherry,342".
So unless your keys are numeric, I think even in Chrome, you're safe. And if your keys are numeric, maybe just prepend them with a string.
As
has been noted, if your keys are numeric
you can prepend them with a string to preserve order.
var qy = {
_141: '256k AAC',
_22: '720p H.264 192k AAC',
_84: '720p 3D 192k AAC',
_140: '128k AAC'
};
Example

Categories

Resources