This must be a duplicate, but I've been Googling "retrieve by value from object javascript" and "javascript lookup object by value" and every variant and got nowhere, so apologies and here goes.
Say I have a JavaScript object like this:
var options = {"ford": "red", "citroen": "blue"};
How do I do look up value blue to get citroen back?
There's always the 'write your own function' route, I guess:
function returnbyValue(options, v):
for (var prop in options) {
if (options.hasOwnProperty(v)) {
if (options[prop] === v) {
return prop;
}
}
}
return null;
but does JavaScript have anything inbuilt, or is there a neater way to do this?
The property of an object can be accessed just like an associative array!
This worked like a charm!
var obj = {
'key': 'val'
};
alert( obj['key'] );
Alternatively, if you wish to use a method you can create a prototype method.
Object.prototype.getPropertyByString = function( str ) {
return this[str];
};
alert( obj.getPropertyByString( 'key' ) );
Edit: Wow I just noticed I failed to answer your question, my apologies! Allow me to get a second chance.
There is no built in function, but my script below works!
var obj = {
'key': 'val'
};
Object.prototype.getKeyByValue = function( object ) {
for(var key in this) {
if(this.key === object) {
return key;
}
}
return null;
};
alert( obj.getKeyByValue( 'val' ) );
It loops through the object and returns the key if it matches a value. This wil work, no matter if the value is an int, string, object, anything. This is because I've used the strict equal comparison ("===") which also checks if the object type is the same.
Also, please note that checking if the property exists is silly if you're looping through all keys of the object anyway. Obviously, when you're looping through all keys, they exist.
There is no such built-in method. And your own function looks good to me. I can't figure out any improvement of it.
Related
So I have been able to create a set function that seems to work correctly. The problem comes when I try to create a 'get' function that searches the hashtable passed on a 'key' passed in as an argument.
The hashing function takes a 'string' and 'size' argument, not a 'key' like all the examples I looked at trying to figure it out. Here is the hashing function I was given...
function hashCode(string, size){
let hash = 0;
if (string.length == 0) return hash;
for (let i = 0; i < string.length; i++) {
const letter = string.charCodeAt(i);
hash = ((hash << 5) - hash) + letter;
hash = hash & hash; // Convert to 32bit integer
}
return Math.abs(hash) % size ;
}
Here is my 'set' 'HashTable' class function andthe 'set' function I wrote...
function HashTable() {
this.SIZE = 16;
this.storage = new Array(this.SIZE);
}
// stores a value in the storage array
HashTable.prototype.set = function(key, value) {
let index = hashCode(value, 16);
if (!this.storage[index]) {
this.storage[index] = [];
}
this.storage[index][key] = value
};
I have tried a few different methods to make the 'get' function work. I have tried iterating through the array and using the .hasOwnProperty method and currently tried to just use dot notation in a loop to find the property (what is shown below). I can't seem to get it to work with the methods I listed and can't think of any other ways to find the key/value pair in the array without being able to get an index from the hashing function.
Here is the 'get' method I am working on...
HashTable.prototype.get = function(key) {
this.storage.forEach((kvpair) => {
if (kvpair.key) {
return kvpair.key
}
})
};
when I create a new instance of the class like this...
let table = new HashTable;
and run the 'set' function...
table.set('key','value');
and console.log 'table' I get this...
HashTable {SIZE: 16, storage: [ , [ key: 'value' ], , , , , , , , , , , , , , ] }
when I attempt to run my 'get' method...
table.get('key')
undefined is logged to the console...
I am just unsure of how to make this 'get' function work without the index... I am obviously not retrieving the value correctly with my loop and dot notation...
Any tips, tricks, ideas, hints, or help will be greatly appreciated!
The problem is that your get method doesn't have a return statement. True, the callback that is passed to forEach has a return statement, but that defines the return value of the callback, not of the get method.
Moreover, returning a value inside a forEach callback is useless: that returned value is going nowhere. forEach does not do anything with it.
Instead I would suggest using find:
HashTable.prototype.get = function(key) {
return this.storage.find(kvpair => kvpair.key)?.key;
};
This will also iterate over the key/value pairs, but find is designed to stop the iteration as soon as the callback returns a truthy value. Since you want key to be truthy, it is enough to return kvpair.key inside that callback. Then find will return the kvpair for which this key is truthy. It then remains to grab again the key property.
The ?. operator will make sure that if the key is not found, and find will return undefined, that no error will occur, but that undefined will be returned instead of accessing a property on undefined.
I slightly changed your get function:
HashTable.prototype.get = function(key) {
var value = null
this.storage.forEach((kvpair) => {
if (kvpair.key) {
value = kvpair.key;
}
})
return value;
};
I have no idea why this works and your code does not...
If anyone can explain why, thank you.
I'm making a dictionary of words, so there are 1,000,000+ words.
The problem comes when I need to store the word constructor. I know this is a reserved word in javascript, but I need to add it to the dictionary.
var dictionary = {}
console.log(dictionary ['word_1'])
//undefined, this is good
console.log(dictionary ['word_2'])
//undefined, this is good
console.log(dictionary ['constructor'])
//[Function: Object]
// this cause initialization code to break
How can I fix this? I could muck with the it like key=key+"_" but that seems bad. Is there anything else I can do?
Instead of using a JS object, you could use the built-in Map type which uses strings/symbols as keys and does not conflict with any existing properties.
Replace
var dictionary = {} with var dictionary = new Map()
Override the constructor key as undefined
According to the MDN Object.prototype page, the only thing that isn't hidden by the __fieldname__ schema is the "constructor field". Thus, you could just initialize your objects via { 'constructor': undefined }.
However, you would have to make sure that in your for .. in statements would filter out all keys with undefined as their value, as it would pick up constructor as a "valid" key (even though it wouldn't before you specifically set it to undefined). I.E.
for(var key in obj) if(obj[key] !== undefined) { /* do things */ }
Check for types when getting/setting
Otherwise, you could just check the type when you 'fetch' or 'store' it. I.E.
function get(obj, key) {
if(typeof obj[key] !== 'function') // optionally, `&& typeof obj[key] !== 'object')`
return obj[key];
else
return undefined;
}
I think you should store all words and translation of them in an array. When you need to translate a word, you can use find method of Array.
For example:
var dict = [
{ word: "abc", translated: "xyz" },
...
];
Then:
var searching_word = "abc";
var translation = dict.find(function (item) {
return item.word == searching_word;
});
console.log(translation.translated);
// --> xyz
To achieve expected result , use below option of using index to get value of any key value
var dictionary = {};
var dictionary1 = {
constructor: "test"
};
//simple function to get key value using index
function getVal(obj, val) {
var keys = Object.keys(obj);
var index = keys.indexOf(val);//get index of key, in our case -contructor
return obj[keys[index]]; // return value using indec of that key
}
console.log(getVal(dictionary, "constructor"));//undefined as expected
console.log(getVal(dictionary1, "constructor"));//test
console.log(dictionary["word_1"]);
//undefined, this is good
console.log(dictionary["word_2"]);
//undefined, this is good
codepen - https://codepen.io/nagasai/pen/LOEGxM
For testing , I gave one object with key-constructor and other object without constructor.
Basically I am getting the index of key first and getting value using index
I'm not really sure what's going on here, but in a nutshell I've seen this:
Object[key](value);
In line 1088 of bootstrap-datetimepicker:
$.fn.datetimepicker = function ( option, val ) {
return this.each(function () {
var $this = $(this),
data = $this.data('datetimepicker'),
options = typeof option === 'object' && option;
if (!data) {
$this.data('datetimepicker', (data = new DateTimePicker(
this, $.extend({}, $.fn.datetimepicker.defaults,options))));
}
// Line below:
if (typeof option === 'string') data[option](val);
});
};
Would anyone be able to answer what is going on?
I thought maybe it was assigning the value to the key in the object but when I tried doing something similar in the developer console (working in chrome v.33) it doesn't work.
Object is a Javascript object that you can declare like this:
var obj = {};
Then a property is created (whose name is contained in the key variable) with a function as its value:
var obj['myfunction'] = function() { alert('Hello!'); };
So now,you have a function stored in your object 'obj' in the 'myfunction' key.
Since it's a function you execute it using '()', which results in:
obj['myfunction']()
var property = 'method';
// multiple ways to access properties
object.method === object['method'] === object[property];
// and you can use any syntax to call the method
// These all call `object.method`:
object.method() === object['method']() === object[property]();
See also https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Member_Operators
To access properties of an object in JavaScript you can either use the dot notation. i.e: Object.property or the string notation (also called bracket notation) Object[property].
Both are valid, though the dot notation doesn't work with property names containing spaces for example, such as Object.property name is invalid, while Object['property name'] is valid.
Given your example, Object[key](value) you are accessing a property of which the name is stored in the key from the Object object. The property happens to be a method and you can execute it passing value as the parameter.
Imagine the object to look like this:
Object = {
myProp: function(newValue){
// do something with newValue
}
}
It would be perfectly fine to call it using the string notation if the method name is stored in a variable:
var key = 'myProp';
Object[key](value);
or if you don't need a variable you can also call it directly using the dot notation:
Object.myProp(value);
Resources: MDN on Property Accessors
Maybe just a hack to do something like:
var method = "create";
var prop = new String();
var str = Object[method](prop);
So you invoke a method create with parameter prop.
If I want to enumerate the properties of an object and want to ignore prototypes, I would use:
var instance = { ... };
for (var prop in instance) {
if (instance.hasOwnProperty(prop)) {
...
}
}
What if instance only has one property, and I want to get that property name? Is there an easier way than doing this:
var instance = { id: "foobar" };
var singleMember = (function() {
for (var prop in instance) {
if (instance.hasOwnProperty(prop)) {
return prop;
}
}
})();
Maybe Object.keys can work for you. If its length returns 1, you can use yourObject[Object.keys[0]] to get the only property of the object. The MDN-link also shows a custom function for use in environments without the keys method1. Code like this:
var obj = {foo:'bar'},
kyz = Object.keys(obj);
if (kyz.length === 1){
alert(obj[kyz[0]]); //=> 'bar'
} else {
/* loop through obj */
}
1 Some older browsers don't support Object.keys. The MDN link supplies code to to make it work in these browsers too. See header Compatibility in the aforementioned MDN page
Shortest form:
instance[Object.keys(instance)[0]];
ES6+ function:
let first = v => v[Object.keys(v)[0]];
Use the function:
first({a:'first', b:'second'}) // return 'first'
var foo = {bar: 1};
console.log(Object.keys(foo).toString());
which will print the string
"bar"
Though my answer is downvoted, it's still worth to know that there is no such thing as order of keys in javascript object. Therefore, in theory, any code build on iterating values can be inconsistent. One approach could be creating an object and to define setter which actually provides counting, ordering and so on, and provide some methods to access this fields. This could be done in modern browsers.
So, to answer you question, in general you approach is still most closs-browser. You can iterate using lodash or any other modern framework wich will hide "hasOwnProperty" complexity from you. As of August'15 Object.keys can be accepted as cross-browser and universal. After all IE8 happened years ago. Still there are some cases when you just don't wont store all set of keys in array. But I'd go with Object.keys - it's more flexible compared to iteration.
Unfortunately, there is no, "list properties" function built in, and there certainly isn't a "getFirstProperty" (especially since there is no guarantee that any property will consistently be "first").
I think you're better off writing a function like this one:
/**
* A means to get all of the keys of a JSON-style object.
* #param obj The object to iterate
* #param count maximum length of returned list (defaults to Infinity).
*/
function getProperties( obj, count )
{
if( isNaN( count ) ) count = Infinity
var keys = []
for( var it in obj )
{
if( keys.length > count ) break;
keys.push( it );
}
return keys;
}
Then, you could access the name though:
instance = {"foo":"bar"}
// String() on an array of < 2 length returns the first value as a string
// or "" if there are no values.
var prop = String(getProperties(instance, 1));
This is an old post, but I ended up writing the following helper function based on Object.keys().
It returns the key and value of the first property.
getFirstPropertyKeyAndValue(sourceObject) {
var result = null;
var ownProperties = Object.keys(sourceObject);
if (ownProperties.length > 0) {
if (ownProperties.length > 1) {
console.warn('Getting first property of an object containing more than 1 own property may result in unexpected results. Ordering is not ensured.', sourceObject);
}
var firstPropertyName = ownProperties[0];
result = {key: firstPropertyName, value: sourceObject[firstPropertyName]};
}
return result;
}
Answers in here all good, and with the caveat that the order may be unreliable (although in practice it seems the order the properties are set tends to stay that way), this quick and dirty method also works:
var obj = {foo: 1, bar: 2};
for(var key in obj) {
//you could use key here if you like
break;
}
//key now contains your first key
or a shorter version should also do it:
for(var key in obj) break;
//key now contains your first key
arr[key] = value;
where key is a jQuery object and value is an array.
Associative arrays don't really exist in JavaScript. However, you can achieve similar functionality using JavaScript objects:
// Create object
var myObject = {
key: value,
helloText: "Hello World!"
};
// Access object in some statement via:
myObject.helloText
// ...or:
myObject["helloText"]
To use an object as a key, you would have to do something like:
var a = {
helloText: "Hello World!"
};
var b = {};
b[a] = "Testing";
alert(b[a]); // Returns "Testing" (at least, in Safari 4.0.4)
Using an object as a key sounds a bit weird, though. Are you sure you need to do this?
Update:
You can't actually use an object as a key in JavaScript. The reason the above code appears to work is that, in the statement b[a] = "Testing";, JavaScript converts a to a string via a.toString(), which results in "[object Object]", and uses this string as the key. So our statement is actually b["[object Object]"] = "Testing"; and our alert statement is exactly the same as alert(b["[object Object]"]);.
Thanks to CMS for pointing this out in the comments!
Update 2:
Tim Down points out that his JavaScript library jshashtable allows you use an object as a key.
You can use jshashtable, which allows any JavaScript object as a key.
Just guessing here, but it seems you're trying to associate some (arbitrary) data with a jQuery object (possibly an element). In that case, why not use the data () method?
$('#el').data (value);
You can't use objects as keys, and assocative arrays are not what they seem in Javascript because all you're doing is setting a property on the array object, when you loop through by the .length it natively doesn't account for the manually defined properties you set.
I suggest storing the elements and arrays inside of object literals, all inside of an array. Eg:
var list = [
{
el:document.body,
arr:[1,2]
}
];
for ( var i = 0, l = list.length; i<l; ++i ) {
alert( list[i]['el'] )
alert( list[i]['arr'][0] )
}
// add elements to the array
list.push({
el:document.body.firstChild,
arr:[3,4]
})
As kprime mentioned in his answer though, it might be better to use .data() if you are using Javascript.
if ( !$(el).data('key') ) {
$(el).data('key', [2,3,4] );
}
I would suggest assigning a unique ID to each element you want to put in the associative container (object in JS) and use the ID as key:
var idCounter = 0;
var container = { };
function storeValue(element, value) {
if (!element.getAttribute('id')) {
element.setAttribute('id', makeID());
}
var id = element.getAttribute('id');
container[id] = value;
}
function makeID() {
return 'unique-id-' + idCounter++;
}
EDIT: This solution assumes that jQuery is not available. If it is, use data('key', value).
every javascript object is an associative array, this is a property build in the language, you do not need to anything special, just use it like that