Path: csiph.com!weretis.net!feeder4.news.weretis.net!feeder5.news.weretis.net!news.solani.org!.POSTED!not-for-mail From: Thomas 'PointedEars' Lahn Newsgroups: comp.lang.javascript Subject: Re: Get object from one of its values Date: Tue, 20 Dec 2016 13:33:17 +0100 Organization: PointedEars Software (PES) Lines: 203 Message-ID: <2298053.9Mp67QZiUf@PointedEars.de> References: Reply-To: Thomas 'PointedEars' Lahn Mime-Version: 1.0 Content-Type: text/plain; charset="UTF-8" Content-Transfer-Encoding: 8Bit X-Trace: solani.org 1482237198 12040 eJwFwYEBwCAIA7CXxLV1O4cC/n/CEj4K1YEo8PIavd6GvI1SRVnC6kCeLsVKD302P47bOT8l4hHY (20 Dec 2016 12:33:18 GMT) X-Complaints-To: abuse@news.solani.org NNTP-Posting-Date: Tue, 20 Dec 2016 12:33:18 +0000 (UTC) User-Agent: KNode/4.14.2 Face: iVBORw0KGgoAAAANSUhEUgAAADAAAAAwBAMAAAClLOS0AAAAGFBMVEXTxa4RFk5dUWANED8PFEfy7+MGBiW+n3ZNF/QuAAACaElEQVQ4jVXUwVOcMBQG8Dc7Rc4PUntdWV2uxjDpGaGeozOp1woar4jd5t/v9wLstMwsA/ntlxdCAgUc1hjTc9/JCZfGoo3wG3HdmdAWrIJRHe7GM/TmpY5VFefuVcAkkPbLIaN8rmPmjloyZxgyR3GuJ4K0AGtJ2htz8o7yqikm759fldQXaMpbDzjKAG+8v+AugVTOPO5DOjLvGtUYQwh0CPjnVMyGd+8/GfUB5nLKJDD2aLDh5HYyMDJGDwQIo2ZmZcKbowNmAdB/AzyFhrmF2MHRb0QJJfaAnwGB6orZhoykLzJtGwF/xpYxI1dswomiUj3gTuAIqCn/4C7cULwGNBtwMTk3Y4LfKB5YUaOKBKYtpplm7u0vip8tU1NWWyI/7XdcSuIDoMt6rVHMWT0DbjHPGqDqZVSa6zleLcUTcIKLoMv3ueJluALtAo9B302zPPlrtiVScRdCjXvVh3e3JpYa/jjkuC9N+LrBMlz/eAN4eQijX2EdLo6c5tGGHwLyHFtXk89dDGHwCVhG9T0S/j55AhRZgkMCmUQXJ49TnS1wnQDvw0eAh9ICeMmEFbCnPMFzjAvsWoEWEFdYEx+S0MoUZ1gT1wId8+AF3Bl2OoEu906AUHx5VLw/gXYg/x84loOah/2UYNrgiwSwGO7RfUzVBbx/kgpckumGOi6QirtD6gkLTitbnxNol47S2jVc2vsN5kPqaAHT8uUdAJM4v/DanjYOwmUjWznGfwB7sGtAtor5BgofDuzaRj4kSQAqDakTsKORa3Q3xKi3gE1fhl71KRMqrdZ2AWNNg/YOhQyrVBnb+i+nEg4bsDA+egAAAABJRU5ErkJggg== Cancel-Lock: sha1:70pwH96sH9pk4/Q0NfUal/HqU/g= X-User-ID: eJwFwYEBwCAIA7CXVilFzxGE/09Y4iaognLRx6ffJq6fYX3ZWUpPVwtzGxbr24trPzyGTrNWIDgoswgy8QNdlhUB X-NNTP-Posting-Host: eJwFwQkBwDAIA0BLA8onJwvFv4TeuYUE84TH8fXVruppwXUO2Ff/sMLmfrhQUnRYyBScMeMDLuwR8Q== X-Face: %i>XG-yXR'\"2P/C_aO%~;2o~?g0pPKmbOw^=NT`tprDEf++D.m7"}HW6.#=U:?2GGctkL,f89@H46O$ASoW&?s}.k+&. If there are one or more objects each of which has a property called > childArray whose value is always a one dimensional array and elements of > the array are unique (ie an element cannot also occur in the childArray > of another object) then if I know the value of one element of a > childArray how do I find the object it's associated with? > > For example if I have: > > var a = {}; > a.childArray = [1,2,3,a,b,c,..]; > var b = {}; > b.childArray = [4,5,6,d,e,f,...]; > var c = {}; > c.childArray = [7,8,9,g,h,i,...]; > ... > > and I'm given the value "5" how do I find that it's associated with "b"? > > The code is dynamically created so I don't know beforehand what or how > many objects will be created. As Jake said correctly, you need to check the objects sequentially (but see bottom). This means that you need to check the variables or properties sequentially that hold references to those objects. If you know the variables or properties, you can create an array of their values. With ECMAScript 2016 methods and syntax: var objects = [a, b, c]; objects.find(obj => obj.hasOwnProperty("childArray") && obj.childArray.indexOf(5) > -1); It might also be necessary to check whether obj.childArray holds a reference to an Array instance, using Array.isArray(). But suppose the less trivial case that there are variables “a” to at most “z” to refer to objects, and you do not know how many, then you will have to use a loop that is checking whether the variable exists and its value is an object reference. For example: var obj; for (var i = "a".charCodeAt(0), end = "z".charCodeAt(0); i <= end; ++i) { var name = String.fromCharCode(i); /* * NOTE: * It is not possible to write a function that determines if a * variable was declared in a specified execution context as * there is no way to refer to a calling execution context. * It is only possible to define such a function in the execution * context that is to be searched. (this != [[Scope]]) */ try { obj = eval(name); } catch (e) { if (e instanceof ReferenceError) continue; } if (typeof obj != "object" || obj == null) continue; if (!obj.hasOwnProperty("childArray") || obj.childArray.indexOf(5) < 0) { obj = null; } else { break; } } if (typeof obj == "object" && obj != null) { /* use obj */ } This can be written in a slightly shorter way using an array of identifiers: /* ["a", "b", "c", …, "z"]; a useful pattern to remember */ var identifiers = Array.apply(null, {length: 26}).map( (() => { var offset = "a".charCodeAt(0); return ((e, i) => String.fromCharCode(i + offset)); })() ); var matchingIdentifier = identifiers.find(name => { var obj; try { obj = eval(name); } catch (e) { if (e instanceof ReferenceError) return false; } if (typeof obj != "object" || obj == null) return false; if (!obj.hasOwnProperty("childArray") || obj.childArray.indexOf(5) < 0) { return false; } return true; }); if (typeof matchingIdentifier == "string") { var obj = eval(matchingIdentifier); } With variables, you can only avoid eval() if you declare potentially missing variables in advance: var a, b, …, z; Then you can generate the array containing the values to be searched as follows: var objects = [a, b, …, z]; And proceed as if you knew how many variables there are in the original code. The caveat here is that you must not use variable names that are already used by the original code. The only way to be certain that this does not happen is declaring variables with “let” (ECMAScript 2015+) instead of “var” within a Block-like statement of your code, and then only the missing ones. If possible, access properties instead of variables in this situation; then you can use Object.property.hasOwnProperty(), or simply “"propertyName" in object” if inheritance is not an issue. Finally, if you need to do this search several times, and the referred objects are not changing in-between, it will improve efficiency greatly if you maintain a map of values to objects instead: var v2o = new Map(); objects.forEach(obj => obj.childArray.forEach(el => v2o.set(el, obj))); Determining the object whose “childArray” property refers to an Array instance that contains the Number value “5” will then be as simple as var needle = v2o.get(5); whereas “needle” will either hold a reference to that object, or “undefined” if there is no matching object in the indexed haystack referred to by “v2o”. [Note that this way a value will map to a reference to the last searched object in which it was found. It is also possible to map a value either to an array of references to matching objects, or to a reference to the first searched matching object. Note also that to know the identifier/name of the variable(s) or property/properties that referred to that object you need to keep an array (also) of names, not (only) object references. Objects have identity, not name.] The Map object is specified as a constructor property of the global object since ECMAScript 2015 as well (ES 2015, § 18.3.4) A simplified polyfill of it is easily written: if (typeof Map != "function") { var Map = function () { /* * NOTE: * Assigns reference to object with empty prototype chain, * to avoid name collisions; a polyfill may be necessary. */ this.items = Object.create(null); }; Map.prototype.get = function (key) { return this.items[key]; }; Map.prototype.set = function (key, value) { this.items[key] = value; }; } For a more elaborate version, that is however not yet written to be ECMAScript 2015 compliant as it was based on the Java implementation (e.g., .put = .set), see . -- PointedEars FAQ: | | Twitter: @PointedEars2 | Please do not cc me./Bitte keine Kopien per E-Mail.