1

I want to loop through 600+ array items in an object and find one particular item based on certain criteria. The array in the object is called "operations" and its items are arrays themselves.

My goal is to get the index of operation's array item which has the deeply nested string "Go".

In the sample below this would be the first element. My problem is that I can check if an array element contains "call" and "draw" but I don't know how to test for the nested dictionary "foobar". I only have basic JavaScript available, no special libraries.

let json = {
  "head": {},
  "operations": [
    [
      "call",
      "w40",
      "draw",
      {
        "parent": "w39",
        "style": [
          "PUSH"
        ],
        "index": 0,
        "text": "Modify"
      }
    ],
    [
      "call",
      "w83.gc",
      "draw",
      {
        "foobar": [
          ["beginPath"],
          [
            "rect",
            0,
            0,
            245,
            80
          ],
          ["fill"],
          [
            "fillText",
            "Go",
            123,
            24
          ],
          [
            "drawImage",
            "rwt-resources/c8af.png",
          ]
        ]
      }
    ],
    [
      "create",
      "w39",
      "rwt.widgets.Menu",
      {
        "parent": "w35",
        "style": [
          "POP_UP"
        ]
      }
    ],
    [
      "call",
      "w39",
      "draw",
      {
        "parent": "w35",
        "style": [
          "POP_UP"
        ]
      }
    ]
  ]
};

let index = "";
let operationList = json.operations;
for (i = 0; i < operationList.length; i++) {
  if (operationList[i].includes('call') && operationList[i].includes('draw')) //missing another check if the dictionary "foobar" exists in this element )
  {
    index = i;
  }
}
document.write(index)
VLAZ
  • 26,331
  • 9
  • 49
  • 67
tzippy
  • 6,458
  • 30
  • 82
  • 151
  • 2
    (Please be aware that the data is a JavaScript object, and is not JSON) – evolutionxbox May 05 '21 at 14:44
  • 2
    Are you saying you don't know how to iterate over the properties of an object? [Iterate through object properties](https://stackoverflow.com/q/8312459/218196). This might also help: [How can I access and process nested objects, arrays or JSON?](https://stackoverflow.com/q/11922383/218196) (it provides examples for how to use loops and recursion to traverse data of unknown structure) – Felix Kling May 05 '21 at 14:45
  • [There's no such thing as a "JSON Object"](http://benalman.com/news/2010/03/theres-no-such-thing-as-a-json/) and [What is the difference between JSON and Object Literal Notation?](https://stackoverflow.com/q/2904131) – VLAZ May 05 '21 at 14:46
  • **FYI**, `index` should be initialized with either `null` or `-1`. If you are storing a number, set the initial value to the same type, not a string. You could just leave the right-hand of the assignment out entirely and just say `let index;` – Mr. Polywhirl May 05 '21 at 14:47
  • Very similar to https://stackoverflow.com/questions/48505147/how-do-i-write-this-recursive-function-to-find-the-max-depth-of-my-object, just stop early when you find the sought value – danh May 05 '21 at 14:55

1 Answers1

0

I'll preface by saying that this data structure is going to be tough to manage in general. I would suggest a scheme for where an operation is an object with well defined properties, rather than just an "array of stuff".

That said, you can use recursion to search the array.

  • If any value in the array is another array, continue with the next level of recursion
  • If any value is an object, search its values
const isPlainObject = require('is-plain-object');

const containsTerm = (value, term) => {
  // if value is an object, search its values
  if (isPlainObject(value)) {
    value = Object.values(value);
  }

  // if value is an array, search within it
  if (Array.isArray(value)) {
    return value.find((element) => {
      return containsTerm(element, term);
    });
  }

  // otherwise, value is a primitive, so check if it matches
  return value === term;
};

const index = object.operations.findIndex((operation) => {
  return containsTerm(operation, 'Go');
});
Eric Haynes
  • 5,126
  • 2
  • 29
  • 36
  • I get an error on the console for the first line: ´ReferenceError: Can't find variable: require´. As I mentioned I have only basic javascript available. Does your answer require any special libraries maybe? – tzippy May 05 '21 at 15:33
  • `require` is how node traditionally handled imports. Assuming you're using ES modules, you want `import isPlainObject from 'is-plain-object'`. You didn't mention your environment, but chances are good that you already have that library from your framework, but if not, it would need to be added as a dependency: https://www.npmjs.com/package/is-plain-object – Eric Haynes May 05 '21 at 18:04
  • Unfortunately i am using iOS shortcuts and it doesn’t seem to be available there. I tested it with Safari on macOS as well and that’s where I got the error on the console. My options seem very limited I guess. What I haven’t been able to accomplish is accessing the foobar object within the array. The dot notation doesn’t seem to work. – tzippy May 05 '21 at 18:07
  • As long as there are only primitives in the values like you have above, you could replace `isPlainObject(value)` with just `typeof(value) === 'object'`. The library is just a bit smarter in that it ensures you don't inspect complex objects. E.g. `typeof(new Date())` is also "object", but you wouldn't really want to look inside of it. – Eric Haynes May 06 '21 at 16:56