I'm attempting to "loop" through an object and grab the name if a certain test passes.
For instance
var x = {
'first':[
'ab',
'abc',
],
'second':[
'sia',
'sss'
],
'third':[
'jp',
'jh'
]
};
As you can see, I have an object containing arrays.
Let's say that I am given the value "sss" .... I am trying to figure out how to get Javascript to output "second" when given the appropriate value.
The same goes for the following scenarios
third for jp
third for jh
first for abc
and so on.
One possibility (where x is your object, and y is your desired array value):
function foo(y) {
for (key in x) {
if (x[key].indexOf(y) > -1) {
return key;
}
}
}
This will find the first key that has the value you are searching for in its array
function myFunction(searchValue, myObject){
for(var i in myObject){
if(myObject.hasOwnProperty(i) && myObject[i].indexOf(searchValue) != -1){
return i;
}
}
}
You know what. No sooner I click Submit Question, did I realized how to do it.
var x = {
'first':[
'ab','abc',
],
'second':[
'sia','sss'
],
'third':[
'jp','jh',
]
};
for(var arr in x) {
var theArr = x[arr];
if(theArr.indexOf("sss") !== -1) console.log(arr) // returns "second"
}
And if you want to exclude properties in the prototype chain use the hasOwnProperty function:
for (var property in obj) {
if (obj.hasOwnProperty(property)) {
console.log('property: ' + property + ' value: ' + obj[property]);
}
}
The in operator will traverse the prototype chain and return all properties in the object.
var x = {
'first':[
'ab',
'abc',
],
'second':[
'sia',
'sss'
],
'third':[
'jp',
'jh'
]
};
var result = Object.keys(x).filter(function(key) {
return x[key].indexOf('sss') > -1;
});
Afterwards, result will be an array containing all keys that contain the value sss, so it could be 0, 1 or more, if duplicates exist.
Related
I have a data structure like the following:
obj
name
parent
name
parent
name
parent
I'm trying to do a recursive function to get the name element for as long as there is a parent element. I've come up with the following code, but it doesn't work because it converts the result to a string (and not an object). Can someone give me some advice on how to best achieve this. The nesting of parent elements is varied, not fixed (even though above I only specified 3 layers). It can range from 1 to 100.
My Desired Result
My end goal is to extract all the 'name' elements from every 'parent' down the hierarchy (and push them to an array).
function getElem(obj){
var result = '';
var parent = '.parent';
var temp = '';
if(!obj.parent){
return obj.name
}
else {
//structure is obj.parent.parent.parent...name
temp += parent;
result = obj + temp + '.name';
console.log(result);
getElem(result);
}
}
getElem(e.data);
function getElem(obj, arr) {
arr = arr || [];
if (obj.name) {
arr.push(obj.name);
}
if (obj.parent) {
return (getElem(obj.parent, arr));
}
else {
return (arr);
}
}
JSFiddle
Assuming that your data structure looks like this
var obj = {
name: 'abc',
parent: {
name: 'def',
parent: {
name: 'ghi',
parent: {
name: 'jkl'
}
}
}
};
function for loop that walks recursively for "parent" key by assigning "parent" key's value in obj and breaks the loop when the key "parent" is not available...
function get_names(obj, key) {
var names = [];
if(key == "undefined") {
key = "parent"; // default value of key
}
do {
if(typeof obj === "undefined") {
break; // breaks the loop when obj/parent is undefined
}
names.push(obj.name); // pushes all the elements named as 'name'
} while(obj = obj.parent);
return names;
}
Logs the array in console
console.log(get_names(obj));
I don't think you need recursion.
function getElem(obj) {
var names = [obj.name];
while (obj.parent) {
obj = obj.parent;
names.push(obj.name);
}
return names;
}
I am trying to implement a Trie in Javascript, which is easy enough but I seem to have hit a road block with my object.
The nodes are structured as follows:
var node = {
children: []
}
Children is an array of nodes that is mapped by a letter in a string. So the string "Test" would look like this:
root = {
children: [
't' => {
children: [
'e' => {
children: [
's' => {
children: [
't' => {
children: []
}
]
}
]
}
]
}
]
};
So each children array should have a length of 1, but if do something like alert(this._root.children.length); I get zero. Any thoughts on why this is happening?
Here is the rest of my implementation:
function Trie() {
this._root = {
children: []
};
}
Trie.prototype = {
//restore constructor
constructor: Trie,
add: function (str){
var curr = this._root,
prev,
currchar;
// For each character in the string
for(var i = 0, j = str.length; i < j; i++) {
// Insert only lowercase letters for efficiency
currchar = str.toLowerCase().charAt(i);
prev = curr;
curr = prev.children[currchar];
// Traverse until we hit a non-existant node
if(typeof(curr) == "undefined") {
// Make a new node
prev.children[currchar] = {
children: []
};
curr = prev.children[currchar];
}
}
}
You are adding properties to the array instance object, not elements to the array. The length property only includes array elements, not properties on the array instance object.
var a = [23, 42];
console.log(a.length); // 2
a['foo'] = 'bar';
console.log(a.length); // 2
a[2] = 1337;
console.log(a.length); // 3
EDITED:
You could instead structure the nodes like this:
var node = {
children: {},
length: function () {
var i = 0;
var k;
for (k in this.children) {
if (this.children.hasOwnProperty(k)) {
i++;
}
}
return i;
}
};
This is inefficient, of course. You should instead define a Node class with the length method on its prototype. Alternatively, define an add method that updates the length property.
I think that the problem is that you use a javasrcipt array as an associative array (as found in other languages). In javascript "associative" arrays are objects that don't have a length property. Normal arrays have numeric indices.
Irrelevant to the question but you might find this useful.
Maybe you want
str.toLowerCase().charCodeAt(i)
instead of
str.toLowerCase().charAt(i)
If str is "f1", the properties you're adding to the children array are "f" and "1" which should cause an array with property named f and length 0, and another child array with length 2 and property 1.
To get only numeric properties, you should make sure your property names are valid array indices -- positive integers representable in 31 bits.
By using charCodeAt instead of charCode, you would get the property names 102 and 49 instead of "f" and 1.
Can an array in JavaScript be associative AND indexed?
I'd like to be able to lookup an item in the array by its position or a key value.
There are no such things as associative arrays in Javascript. You can use object literals, which look like associative arrays, but they have unordered properties. Regular Javascript arrays are based on integer indexes, and can't be associative.
For example, with this object:
var params = {
foo: 1,
bar: 0,
other: 2
};
You can access properties from the object, for example:
params["foo"];
And you can also iterate over the object using the for...in statement:
for(var v in params) {
//v is equal to the currently iterated property
}
However, there is no strict rule on the order of property iteration - two iterations of your object literal could return the properties in different orders.
After reading the Wikipedia definition of associative array, I'm going to break with traditional JavaScript lore and say, "yes, JavaScript does have associative arrays." With JavaScript arrays, you can add, reassign, remove, and lookup values by their keys (and the keys can be quoted strings), which is what Wikipedia says associative arrays should be able to do.
However, you seem to be asking something different--whether you can look up the same value by either index or key. That's not a requirement of associative arrays (see the Wikipedia article.) Associative arrays don't have to give you the ability to get a value by index.
JavaScript arrays are very closely akin to JavaScript objects.
arr=[];
arr[0]="zero";
arr[1]="one";
arr[2]="two";
arr["fancy"]="what?";
Yes, that's an array, and yes, you can get away with non-numeric indices. (If you're curious, after all this, arr.length is 3.)
In most cases, I think you should stick to numeric indices when you use arrays. That what most programmers expect, I think.
The link is to my blog post about the subject.
Native JS objects only accept strings as property names, which is true even for numeric array indices; arrays differ from vanilla objects only insofar as most JS implementations will store numerically indexed properties differently (ie in an actual array as long as they are dense) and setting them will trigger additional operations (eg adjustment of the length property).
If you're looking for a map which accepts arbitrary keys, you'll have to use a non-native implementation. The script is intended for fast iteration and not random-access by numeric indices, so it might nor be what you're looking for.
A barebones implementation of a map which would do what you're asking for could look like this:
function Map() {
this.length = 0;
this.store = {};
}
Map.prototype.get = function(key) {
return this.store.hasOwnProperty(key) ?
this.store[key] : undefined;
};
Map.prototype.put = function(key, value, index) {
if(arguments.length < 3) {
if(this.store.hasOwnProperty(key)) {
this.store[key].value = value;
return this;
}
index = this.length;
}
else if(index >>> 0 !== index || index >= 0xffffffff)
throw new Error('illegal index argument');
if(index >= this.length)
this.length = index + 1;
this[index] = this.store[key] =
{ index : index, key : key, value : value };
return this;
};
The index argument of put() is optional.
You can access the values in a map map either by key or index via
map.get('key').value
map[2].value
var myArray = Array();
myArray["first"] = "Object1";
myArray["second"] = "Object2";
myArray["third"] = "Object3";
Object.keys(myArray); // returns ["first", "second", "third"]
Object.keys(myArray).length; // returns 3
if you want the first element then you can use it like so:
myArray[Object.keys(myArray)[0]]; // returns "Object1"
The order in which objects appear in an associative javascript array is not defined, and will differ across different implementations. For that reason you can't really count on a given associative key to always be at the same index.
EDIT:
as Perspx points out, there aren't really true associative arrays in javascript. The statement foo["bar"] is just syntactic sugar for foo.bar
If you trust the browser to maintain the order of elements in an object, you could write a function
function valueForIndex(obj, index) {
var i = 0;
for (var key in obj) {
if (i++ == index)
return obj[key];
}
}
var stuff = [];
stuff[0] = "foo";
stuff.bar = stuff[0]; // stuff.bar can be stuff["bar"] if you prefer
var key = "bar";
alert(stuff[0] + ", " + stuff[key]); // shows "foo, foo"
I came here to wanting to know if this is bad practice or not, and instead found a lot of people appearing not to understand the question.
I wanted to have a data structure that was ordered but could be indexed by key, so that it wouldn't require iteration for every lookup.
In practical terms this is quite simple, but I still haven't read anything on whether it's a terrible practice or not.
var roygbiv = [];
var colour = { key : "red", hex : "#FF0000" };
roygbiv.push(colour);
roygbiv[colour.key] = colour;
...
console.log("Hex colours of the rainbow in order:");
for (var i = 0; i < roygbiv.length; i++) {
console.log(roygbiv[i].key + " is " + roygbiv[i].hex);
}
// input = "red";
console.log("Hex code of input colour:");
console.log(roygbiv[input].hex);
The important thing is to never change the value of array[index] or array[key] directly once the object is set up or the values will no longer match. If the array contains objects you can change the properties of those objects and you will be able to access the changed properties by either method.
Although I agree with the answers given you can actually accomplish what you are saying with getters and setters. For example:
var a = [1];
//This makes a["blah"] refer to a[0]
a.__defineGetter__("blah", function(){return this[0]});
//This makes a["blah"] = 5 actually store 5 into a[0]
a.__defineSetter__("blah", function(val){ this[0] = val});
alert(a["blah"]); // emits 1
a["blah"] = 5;
alert(a[0]); // emits 5
Is this what you are looking for? i think theres a different more modern way to do getters and setters but cant remember.
The tide has changed on this one. Now you can do that... and MORE! Using Harmony Proxies you could definitely solve this problem in many ways.
You'll have to verify that your targeted environments support this with maybe a little help from the harmony-reflect shim.
There's a really good example on the Mozilla Developer Network on using a Proxy to find an array item object by it's property which pretty much sums it up.
Here's my version:
var players = new Proxy(
[{
name: 'monkey',
score: 50
}, {
name: 'giraffe',
score: 100
}, {
name: 'pelican',
score: 150
}], {
get: function(obj, prop) {
if (prop in obj) {
// default behavior
return obj[prop];
}
if (typeof prop == 'string') {
if (prop == 'rank') {
return obj.sort(function(a, b) {
return a.score > b.score ? -1 : 1;
});
}
if (prop == 'revrank') {
return obj.sort(function(a, b) {
return a.score < b.score ? -1 : 1;
});
}
var winner;
var score = 0;
for (var i = 0; i < obj.length; i++) {
var player = obj[i];
if (player.name == prop) {
return player;
} else if (player.score > score) {
score = player.score;
winner = player;
}
}
if (prop == 'winner') {
return winner;
}
return;
}
}
});
console.log(players[0]); // { name: 'monkey', score: 50 }
console.log(players['monkey']); // { name: 'monkey', score: 50 }
console.log(players['zebra']); // undefined
console.log(players.rank); // [ { name: 'pelican', score: 150 },{ name: 'giraffe', score: 100 }, { name: 'monkey', score: 50 } ]
console.log(players.revrank); // [ { name: 'monkey', score: 50 },{ name: 'giraffe', score: 100 },{ name: 'pelican', score: 150 } ]
console.log(players.winner); // { name: 'pelican', score: 150 }
The latest MDN documentation makes it quiet clear that Array index must be integers.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array
let arr=[];
arr[0]="zero";
arr[1]="one";
arr[2]="two";
arr["fancy"]="what?";
//Arrays cannot use strings as element indexes (as in an associative array) but must use integers.
//Setting non-integers using bracket notation will not set an element to the Array List itself
//A non-integer will set a variable associated with that ARRAY Object property collection
let denseKeys = [...arr.keys()];
console.log(denseKeys);//[ 0, 1, 2 ]
console.log("ARRAY Keys:"+denseKeys.length);//3
let sparseKeys = Object.keys(arr);
console.log(sparseKeys);//[ '0', '1', '2', 'fancy' ]
console.log("Object Keys:"+sparseKeys.length);//4
const iterator = arr.keys();
for (const key of iterator) {
console.log(key);//0,1,2
}
Yes.
test = new Array();
test[0] = 'yellow';
test['banana'] = 0;
alert(test[test['banana']]);
Consider:
var object = {
foo: {},
bar: {},
baz: {}
}
How would I do this:
var first = object[0];
console.log(first);
Obviously, that doesn’t work because the first index is named foo,
not 0.
console.log(object['foo']);
works, but I don’t know it’s named foo. It could be named anything. I just want the first.
Just for fun this works in JS 1.8.5
var obj = {a: 1, b: 2, c: 3};
Object.keys(obj)[0]; // "a"
This matches the same order that you would see doing
for (o in obj) { ... }
If you want something concise try:
for (first in obj) break;
alert(first);
wrapped as a function:
function first(obj) {
for (var a in obj) return a;
}
they're not really ordered, but you can do:
var first;
for (var i in obj) {
if (obj.hasOwnProperty(i) && typeof(i) !== 'function') {
first = obj[i];
break;
}
}
the .hasOwnProperty() is important to ignore prototyped objects.
This will not give you the first one as javascript objects are unordered, however this is fine in some cases.
myObject[Object.keys(myObject)[0]]
If the order of the objects is significant, you should revise your JSON schema to store the objects in an array:
[
{"name":"foo", ...},
{"name":"bar", ...},
{"name":"baz", ...}
]
or maybe:
[
["foo", {}],
["bar", {}],
["baz", {}]
]
As Ben Alpert points out, properties of Javascript objects are unordered, and your code is broken if you expect them to enumerate in the same order that they are specified in the object literal—there is no "first" property.
for first key of object you can use
console.log(Object.keys(object)[0]);//print key's name
for value
console.log(object[Object.keys(object)[0]]);//print key's value
There is no way to get the first element, seeing as "hashes" (objects) in JavaScript have unordered properties. Your best bet is to store the keys in an array:
var keys = ["foo", "bar", "baz"];
Then use that to get the proper value:
object[keys[0]]
ES6
const [first] = Object.keys(obj)
Using underscore you can use _.pairs to get the first object entry as a key value pair as follows:
_.pairs(obj)[0]
Then the key would be available with a further [0] subscript, the value with [1]
I had the same problem yesterday. I solved it like this:
var obj = {
foo:{},
bar:{},
baz:{}
},
first = null,
key = null;
for (var key in obj) {
first = obj[key];
if(typeof(first) !== 'function') {
break;
}
}
// first is the first enumerated property, and key it's corresponding key.
Not the most elegant solution, and I am pretty sure that it may yield different results in different browsers (i.e. the specs says that enumeration is not required to enumerate the properties in the same order as they were defined). However, I only had a single property in my object so that was a non-issue. I just needed the first key.
You could do something like this:
var object = {
foo:{a:'first'},
bar:{},
baz:{}
}
function getAttributeByIndex(obj, index){
var i = 0;
for (var attr in obj){
if (index === i){
return obj[attr];
}
i++;
}
return null;
}
var first = getAttributeByIndex(object, 0); // returns the value of the
// first (0 index) attribute
// of the object ( {a:'first'} )
To get the first key of your object
const myObject = {
'foo1': { name: 'myNam1' },
'foo2': { name: 'myNam2' }
}
const result = Object.keys(myObject)[0];
// result will return 'foo1'
Based on CMS answer. I don't get the value directly, instead I take the key at its index and use this to get the value:
Object.keyAt = function(obj, index) {
var i = 0;
for (var key in obj) {
if ((index || 0) === i++) return key;
}
};
var obj = {
foo: '1st',
bar: '2nd',
baz: '3rd'
};
var key = Object.keyAt(obj, 1);
var val = obj[key];
console.log(key); // => 'bar'
console.log(val); // => '2nd'
My solution:
Object.prototype.__index = function(index)
{
var i = -1;
for (var key in this)
{
if (this.hasOwnProperty(key) && typeof(this[key])!=='function')
++i;
if (i >= index)
return this[key];
}
return null;
}
aObj = {'jack':3, 'peter':4, '5':'col', 'kk':function(){alert('hell');}, 'till':'ding'};
alert(aObj.__index(4));
Say you have a javascript object like this:
var data = { foo: 'bar', baz: 'quux' };
You can access the properties by the property name:
var foo = data.foo;
var baz = data["baz"];
But is it possible to get these values if you don't know the name of the properties? Does the unordered nature of these properties make it impossible to tell them apart?
In my case I'm thinking specifically of a situation where a function needs to accept a series of name-value pairs, but the names of the properties may change.
My thoughts on how to do this so far is to pass the names of the properties to the function along with the data, but this feels like a hack. I would prefer to do this with introspection if possible.
You can loop through keys like this:
for (var key in data) {
console.log(key);
}
This logs "Name" and "Value".
If you have a more complex object type (not just a plain hash-like object, as in the original question), you'll want to only loop through keys that belong to the object itself, as opposed to keys on the object's prototype:
for (var key in data) {
if (data.hasOwnProperty(key)) {
console.log(key);
}
}
As you noted, keys are not guaranteed to be in any particular order. Note how this differs from the following:
for each (var value in data) {
console.log(value);
}
This example loops through values, so it would log Property Name and 0. N.B.: The for each syntax is mostly only supported in Firefox, but not in other browsers.
If your target browsers support ES5, or your site includes es5-shim.js (recommended), you can also use Object.keys:
var data = { Name: 'Property Name', Value: '0' };
console.log(Object.keys(data)); // => ["Name", "Value"]
and loop with Array.prototype.forEach:
Object.keys(data).forEach(function (key) {
console.log(data[key]);
});
// => Logs "Property Name", 0
Old versions of JavaScript (< ES5) require using a for..in loop:
for (var key in data) {
if (data.hasOwnProperty(key)) {
// do something with key
}
}
ES5 introduces Object.keys and Array#forEach which makes this a little easier:
var data = { foo: 'bar', baz: 'quux' };
Object.keys(data); // ['foo', 'baz']
Object.keys(data).map(function(key){ return data[key] }) // ['bar', 'quux']
Object.keys(data).forEach(function (key) {
// do something with data[key]
});
ES2017 introduces Object.values and Object.entries.
Object.values(data) // ['bar', 'quux']
Object.entries(data) // [['foo', 'bar'], ['baz', 'quux']]
for(var property in data) {
alert(property);
}
You often will want to examine the particular properties of an instance of an object,
without all of it's shared prototype methods and properties:
Obj.prototype.toString= function(){
var A= [];
for(var p in this){
if(this.hasOwnProperty(p)){
A[A.length]= p+'='+this[p];
}
}
return A.join(', ');
}
function getDetailedObject(inputObject) {
var detailedObject = {}, properties;
do {
properties = Object.getOwnPropertyNames( inputObject );
for (var o in properties) {
detailedObject[properties[o]] = inputObject[properties[o]];
}
} while ( inputObject = Object.getPrototypeOf( inputObject ) );
return detailedObject;
}
This will get all properties and their values (inherited or own, enumerable or not) in a new object. original object is untouched. Now new object can be traversed using
var obj = { 'b': '4' }; //example object
var detailedObject = getDetailedObject(obj);
for(var o in detailedObject) {
console.log('key: ' + o + ' value: ' + detailedObject[o]);
}
var obj = {
a: [1, 3, 4],
b: 2,
c: ['hi', 'there']
}
for(let r in obj){ //for in loop iterates all properties in an object
console.log(r) ; //print all properties in sequence
console.log(obj[r]);//print all properties values
}
You can use Object.keys(), "which returns an array of a given object's own enumerable property names, in the same order as we get with a normal loop."
You can use any object in place of stats:
var stats = {
a: 3,
b: 6,
d: 7,
erijgolekngo: 35
}
/* this is the answer here */
for (var key in Object.keys(stats)) {
var t = Object.keys(stats)[key];
console.log(t + " value =: " + stats[t]);
}
var attr, object_information='';
for(attr in object){
//Get names and values of propertys with style (name : value)
object_information += attr + ' : ' + object[attr] + '\n';
}
alert(object_information); //Show all Object