f



Get object from one of its values

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.

Andrew Poulos
0
Andrew
12/20/2016 3:43:21 AM
comp.lang.javascript 38370 articles. 2 followers. javascript4 (1315) is leader. Post Follow

5 Replies
514 Views

Similar Articles

[PageSpeed] 59

Am 20.12.2016 um 04:43 schrieb Andrew Poulos:
> 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?
>

You sequentially check all objects - maybe stop once found - and their 
respective childArray properties.

e.g. (if conveniently collected in a useful way)
objectsContainer.find(o => o.childArray.indexOf(5) > -1)

> 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.
>

Are they collected somewhere at least?
or
Are they (assigned to) global variables?
or
Are they (assigned to) local variables?

0
Jake
12/20/2016 9:42:01 AM
Andrew Poulos wrote:

> 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 
<https://github.com/PointedEars/JSX/blob/517e2fa56831a3dff8eb2bb7c7e7cbe45c5d0a86/map.js>.

-- 
PointedEars
FAQ: <http://PointedEars.de/faq> | <http://PointedEars.de/es-matrix>
<https://github.com/PointedEars> | <http://PointedEars.de/wsvn/>
Twitter: @PointedEars2 | Please do not cc me./Bitte keine Kopien per E-Mail.
0
Thomas
12/20/2016 12:33:17 PM
On Tue, 20 Dec 2016 14:43:21 +1100, Andrew Poulos
<ap_prog@hotmail.com> wrote:

  <snip>
>var a =3D {};
>     a.childArray =3D [1,2,3,a,b,c,..];
>var b =3D {};
>     b.childArray =3D [4,5,6,d,e,f,...];
>var c =3D {};
>     c.childArray =3D [7,8,9,g,h,i,...];
>...
>
>and I'm given the value "5" how do I find that it's associated with "b"?
  <snip>

One way is for 5 to have a pointer back to b. Replacing 5 by an object
with 5 as one property, value, and b as another, owner, would make
this possible.

But if 5 came from the keyboard then obviously this wouldn't help.
So another way is to record the (child value, owner object) in a Map,
updated whenever an array changes.

  John
0
John
12/20/2016 6:21:30 PM
On 20/12/2016 8:42 PM, Jake Jarvis wrote:
> Am 20.12.2016 um 04:43 schrieb Andrew Poulos:
>> 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?
>>
>
> You sequentially check all objects - maybe stop once found - and their
> respective childArray properties.
>
> e.g. (if conveniently collected in a useful way)
> objectsContainer.find(o => o.childArray.indexOf(5) > -1)
>
>> 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.
>>
>
> Are they collected somewhere at least?

I thought "no" but when I created an number of test files I discovered 
that any object that contains a childArray property has an id that 
begins with "og". So it should be straightfoward enough to collect.

> Are they (assigned to) global variables?

Yes

> Are they (assigned to) local variables?

No.

Andrew poulos
0
Andrew
12/20/2016 8:25:05 PM
Thomas 'PointedEars' Lahn wrote:

>     if (!obj.hasOwnProperty("childArray") || obj.childArray.indexOf(5) < 0)
>     {
>       return false;
>     }
> 
>     return true;

This can be simplified to

    return (obj.hasOwnProperty("childArray")
            && obj.childArray.indexOf(5) > -1);

or

    return (obj.childArray && obj.childArray.indexOf(5) > -1);

if it does not matter that the “childArray” property is inherited.
(But it is assumed here that it holds a reference to an Array instance,
and that the Array.prototype.indexOf() method of ES 5+ is implemented.)

-- 
PointedEars
FAQ: <http://PointedEars.de/faq> | <http://PointedEars.de/es-matrix>
<https://github.com/PointedEars> | <http://PointedEars.de/wsvn/>
Twitter: @PointedEars2 | Please do not cc me./Bitte keine Kopien per E-Mail.
0
Thomas
12/20/2016 10:10:13 PM
Reply: