Skip to content Skip to sidebar Skip to footer

Find Object In Array With Subarray Checking An Property

I have the array below and each element has another array called FunctionalityChildren, I need find the unique object that contains the property ActionFull equal a variable, for ex

Solution 1:

Here's how we expect our generic deepFind function to work

deepFind (x => x.ActionFull === '/budget', bigArray)
// { FunctionalityID: 105, Name: 'Budget', ActionFull: '/budget' ... }

deepFind (x => x.ActionFull === '/budget/allocation', bigArray)
// { FunctionalityID: 106, Name: 'Allocation', ActionFull: '/budget/allocation' }

I'm going to give you the imperative style solution in hopes that this gets you thinking about how you will need to structure your function calls. Notice that this program will begin iterating thru a possible set of solutions but it stops iterating and returns a result as soon as a match is found. Using Array#reduce or Array#map or Array#filter is inadequate for this task as they do not have the short-circuiting behavior we're looking for

Run the program below in your browser, this time with a simplified data set. It's should be easy to follow how we arrive at the result

const data =
  [ { a: 1, b: 1 }
  , { a: 2, b: 2, c: { d: [ { e: 2 } ] } }
  , { a: 3, b: { c: { d: { e: { f: 3 } } } } }
  ]

constdeepFind = (f, obj = {}) =>
{ if (Object (obj) === obj)
  { if (f (obj) === true)
      return obj

    for (const [ k, v ] ofObject.entries (obj))
    { const res =
        deepFind (f, v)
      
      if (res !== undefined)
        return res
    }
  }

  returnundefined
}

console.log
  ( deepFind (x => x.a === 1, data)             // { a: 1, b: 1 }
  , deepFind (x => x.e === 2, data)             // { e: 2 }
  , deepFind (x =>Array.isArray(x.d), data)    // { d: [ { e: 2 } ] }
  , deepFind (x => x.f === 3, data)             // { f: 3 }
  , deepFind (x => x.e && x.e.f === 3, data)    // { e: { f: 3 } }
  , deepFind (x => x.z === 9, data)             // undefined
  )

deepFind works for all objects, arrays included

const alpha =
  [ [ 'a', 'b', 'c' ], [ 'd', 'e', 'f' ], [ 'g', 'h', 'i' ] ]

deepFind (x => x [1] === 'h', alpha)
// [ 'g', 'h', 'i', ]

deepFind (([ _0, _1, _2 ]) => _2 === 'f', alpha)
// [ 'd', 'e', 'f' ]

Expressing deepFind as a functional program requires only the translation of an iterative loop to a recursive function with state parameters. Because you design the recursive function yourself, you can encode the short-circuit behavior this program requires.

Below, deepFind is written using a pure functional expression. State parameters v and rest are added but only f and o are meant to be specified by the user, like we did above. If you didn't want these as part your function's public interface, an internal auxiliary function could be used instead.

constidentity = x =>
  x

constNone =
  Symbol ()

constdeepFind = (f = identity, o = {}, [ _, v ] = [ None, None ], ...rest) =>
  Object (o) === o
    ? f (o) === true
      ? o
      : v === None
        ? deepFind (f, null, ...Object.entries (o))
        : deepFind (f, v, ...rest, ...Object.entries (o)) 
    : v === None
      ? undefined
      : deepFind (f, v, ...rest )

Re-run the program to verify that the output is indeed the same

constidentity = x =>
  x

constNone =
  Symbol ()

constdeepFind = (f = identity, o = {}, [ _, v ] = [ None, None ], ...rest) =>
  Object (o) === o
    ? f (o) === true
      ? o
      : v === None
        ? deepFind (f, null, ...Object.entries (o))
        : deepFind (f, v, ...rest, ...Object.entries (o)) 
    : v === None
      ? undefined
      : deepFind (f, v, ...rest )

const data =
  [ { a: 1, b: 1 }
  , { a: 2, b: 2, c: { d: [ { e: 2 } ] } }
  , { a: 3, b: { c: { d: { e: { f: 3 } } } } }
  ]

console.log
  ( deepFind (x => x.a === 1, data)             // { a: 1, b: 1 }
  , deepFind (x => x.e === 2, data)             // { e: 2 }
  , deepFind (x =>Array.isArray(x.d), data)    // { d: [ { e: 2 } ] }
  , deepFind (x => x.f === 3, data)             // { f: 3 }
  , deepFind (x => x.e && x.e.f === 3, data)    // { e: { f: 3 } }
  , deepFind (x => x.z === 9, data)             // undefined
  )

const alpha =
  [ [ 'a', 'b', 'c' ], [ 'd', 'e', 'f' ], [ 'g', 'h', 'i' ] ]

console.log
  ( deepFind (x => x [1] === 'h', alpha)              // [ 'g', 'h', 'i', ]
  , deepFind (([ _0, _1, _2 ]) => _2 === 'f', alpha)  // [ 'd', 'e', 'f' ]
  )

Lastly, here's a deepFindAll. In this variation of the program, instead of getting a single answer or undefined, we get an array of zero or more results. This demonstrates the auxiliary loop I mentioned in the previous example and also a beautiful use case for generators.

As an exercise, I encourage you to rewrite deepFindAll below using a functional expression in place of the auxiliary generator

constdeepFindAll = (f, o = {}) =>
{ const aux =
    function* (f, o)
    { if (Object (o) === o)
      { if (f (o) === true)
          yield o
        for (const [ _, v ] ofObject.entries (o))
          yield* aux (f, v)
      }
    }
  returnArray.from (aux (f, o))
}

const data =
  [ { a: 1, b: 1 }
  , { a: 2, b: 2, c: { d: [ { e: 2 } ] } }
  , { a: 3, b: { c: { d: { e: { f: 3 } } } } }
  ]

console.log
  ( deepFindAll (x => x.a === 1 || x.e === 2, data)  // [ { a: 1, b: 1 }, { e: 2 } ]
  , deepFindAll (x => x.e !== undefined, data)       //[ { e: 2 }, { e: { f: 3 } } ]
  , deepFindAll (x => x.z === 9, data)               // []
  )

Solution 2:

Since you have to find the unique item, you can use find method. The find() method returns the value of the first element in the array that satisfies the provided testing function. Otherwise undefined is returned.

Also, you can use map method and spread syntax in order to find out all the children elements from the bigArray elements.

The map() method creates a new array with the results of calling a provided callback function on every element in the calling array.

let bigArray = [ { "FunctionalityID": 114, "Name": "General Register", "Action": "/general-register", "Icon": "settings_input_composite", "System_ID": 21, "FunctionalityFather_ID": null, "Active": 1, "Priority": 1, "FunctionalityChildren": [ { "FunctionalityID": 115, "Name": "Supplier", "Action": "/supplier", "Icon": "perm_contact_calendar", "System_ID": 21, "FunctionalityFather_ID": 114, "Active": 1, "Priority": 1, "ProfileFunctionalities": [ { "ProfileFunctionalityID": 1251, "Profile_ID": 68, "Functionality_ID": 115, "CanInsert": true, "CanUpdate": true, "CanDelete": true } ], "ActionFull": "/general-register/supplier" }, { "FunctionalityID": 116, "Name": "RPA", "Action": "/rpa", "Icon": "view_day", "System_ID": 21, "FunctionalityFather_ID": 114, "Active": 1, "Priority": 2, "ProfileFunctionalities": [ { "ProfileFunctionalityID": 1252, "Profile_ID": 68, "Functionality_ID": 116, "CanInsert": true, "CanUpdate": true, "CanDelete": true } ], "ActionFull": "/general-register/rpa" }, { "FunctionalityID": 117, "Name": "Cost Center", "Action": "/cost-center", "Icon": "home", "System_ID": 21, "FunctionalityFather_ID": 114, "Active": 1, "Priority": 3, "ProfileFunctionalities": [ { "ProfileFunctionalityID": 1253, "Profile_ID": 68, "Functionality_ID": 117, "CanInsert": true, "CanUpdate": true, "CanDelete": true } ], "ActionFull": "/general-register/cost-center" }, { "FunctionalityID": 118, "Name": "Departament", "Action": "/departament", "Icon": "donut_small", "System_ID": 21, "FunctionalityFather_ID": 114, "Active": 1, "Priority": 4, "ProfileFunctionalities": [ { "ProfileFunctionalityID": 1254, "Profile_ID": 68, "Functionality_ID": 118, "CanInsert": true, "CanUpdate": true, "CanDelete": true } ], "ActionFull": "/general-register/departament" }, { "FunctionalityID": 119, "Name": "Product Line", "Action": "/product-line", "Icon": "view_headline", "System_ID": 21, "FunctionalityFather_ID": 114, "Active": 1, "Priority": 5, "ProfileFunctionalities": [ { "ProfileFunctionalityID": 1255, "Profile_ID": 68, "Functionality_ID": 119, "CanInsert": true, "CanUpdate": true, "CanDelete": true } ], "ActionFull": "/general-register/product-line" }, { "FunctionalityID": 120, "Name": "Product", "Action": "/product", "Icon": "shopping_cart", "System_ID": 21, "FunctionalityFather_ID": 114, "Active": 1, "Priority": 6, "ProfileFunctionalities": [ { "ProfileFunctionalityID": 1256, "Profile_ID": 68, "Functionality_ID": 120, "CanInsert": true, "CanUpdate": true, "CanDelete": true } ], "ActionFull": "/general-register/product" } ], "ProfileFunctionalities": [ { "ProfileFunctionalityID": 1250, "Profile_ID": 68, "Functionality_ID": 114, "CanInsert": false, "CanUpdate": false, "CanDelete": false } ], "ActionFull": "/general-register", "HasFunctionalities": true, "model": false }, { "FunctionalityID": 99, "Name": "Budget Account", "Action": "/budget-account", "Icon": "monetization_on", "System_ID": 21, "FunctionalityFather_ID": null, "Active": 1, "Priority": 2, "FunctionalityChildren": [ { "FunctionalityID": 100, "Name": "Sector", "Action": "/sector", "Icon": "account_balance", "System_ID": 21, "FunctionalityFather_ID": 99, "Active": 1, "Priority": 1, "ProfileFunctionalities": [ { "ProfileFunctionalityID": 1258, "Profile_ID": 68, "Functionality_ID": 100, "CanInsert": true, "CanUpdate": true, "CanDelete": true } ], "ActionFull": "/budget-account/sector" }, { "FunctionalityID": 101, "Name": "Group", "Action": "/group", "Icon": "group_work", "System_ID": 21, "FunctionalityFather_ID": 99, "Active": 1, "Priority": 2, "ProfileFunctionalities": [ { "ProfileFunctionalityID": 1259, "Profile_ID": 68, "Functionality_ID": 101, "CanInsert": true, "CanUpdate": true, "CanDelete": true } ], "ActionFull": "/budget-account/group" }, { "FunctionalityID": 102, "Name": "Account", "Action": "/account", "Icon": "attach_money", "System_ID": 21, "FunctionalityFather_ID": 99, "Active": 1, "Priority": 3, "ProfileFunctionalities": [ { "ProfileFunctionalityID": 1260, "Profile_ID": 68, "Functionality_ID": 102, "CanInsert": true, "CanUpdate": true, "CanDelete": true } ], "ActionFull": "/budget-account/account" }, { "FunctionalityID": 103, "Name": "Budget", "Action": "/budget", "Icon": "credit_card", "System_ID": 21, "FunctionalityFather_ID": 99, "Active": 1, "Priority": 4, "ProfileFunctionalities": [ { "ProfileFunctionalityID": 1261, "Profile_ID": 68, "Functionality_ID": 103, "CanInsert": true, "CanUpdate": true, "CanDelete": true } ], "ActionFull": "/budget-account/budget" } ], "ProfileFunctionalities": [ { "ProfileFunctionalityID": 1257, "Profile_ID": 68, "Functionality_ID": 99, "CanInsert": false, "CanUpdate": false, "CanDelete": false } ], "ActionFull": "/budget-account", "HasFunctionalities": true, "model": false }, { "FunctionalityID": 105, "Name": "Budget", "Action": "/budget", "Icon": "credit_card", "System_ID": 21, "FunctionalityFather_ID": null, "Active": 1, "Priority": 3, "FunctionalityChildren": [ { "FunctionalityID": 106, "Name": "Allocation", "Action": "/allocation", "Icon": "note_add", "System_ID": 21, "FunctionalityFather_ID": 105, "Active": 1, "Priority": 1, "ProfileFunctionalities": [ { "ProfileFunctionalityID": 1272, "Profile_ID": 68, "Functionality_ID": 106, "CanInsert": true, "CanUpdate": true, "CanDelete": true } ], "ActionFull": "/budget/allocation" }, { "FunctionalityID": 107, "Name": "Copy", "Action": "/copy", "Icon": "content_copy", "System_ID": 21, "FunctionalityFather_ID": 105, "Active": 1, "Priority": 2, "ProfileFunctionalities": [ { "ProfileFunctionalityID": 1273, "Profile_ID": 68, "Functionality_ID": 107, "CanInsert": true, "CanUpdate": true, "CanDelete": true } ], "ActionFull": "/budget/copy" }, { "FunctionalityID": 108, "Name": "In And Out", "Action": "/in-and-out", "Icon": "swap_vertical_circle", "System_ID": 21, "FunctionalityFather_ID": 105, "Active": 1, "Priority": 3, "ProfileFunctionalities": [ { "ProfileFunctionalityID": 1274, "Profile_ID": 68, "Functionality_ID": 108, "CanInsert": true, "CanUpdate": true, "CanDelete": true } ], "ActionFull": "/budget/in-and-out" }, { "FunctionalityID": 109, "Name": "Account Accounting", "Action": "/account-accounting", "Icon": "assignment", "System_ID": 21, "FunctionalityFather_ID": 105, "Active": 1, "Priority": 4, "ProfileFunctionalities": [ { "ProfileFunctionalityID": 1275, "Profile_ID": 68, "Functionality_ID": 109, "CanInsert": true, "CanUpdate": true, "CanDelete": true } ], "ActionFull": "/budget/account-accounting" }, { "FunctionalityID": 110, "Name": "Event", "Action": "/eventos", "Icon": "shopping_cart", "System_ID": 21, "FunctionalityFather_ID": 105, "Active": 1, "Priority": 5, "ProfileFunctionalities": [ { "ProfileFunctionalityID": 1276, "Profile_ID": 68, "Functionality_ID": 110, "CanInsert": true, "CanUpdate": true, "CanDelete": true } ], "ActionFull": "/budget/eventos" }, { "FunctionalityID": 111, "Name": "Copy Counter", "Action": "/copy-counter", "Icon": "swap_vertical_circle", "System_ID": 21, "FunctionalityFather_ID": 105, "Active": 1, "Priority": 6, "ProfileFunctionalities": [ { "ProfileFunctionalityID": 1277, "Profile_ID": 68, "Functionality_ID": 111, "CanInsert": true, "CanUpdate": true, "CanDelete": true } ], "ActionFull": "/budget/copy-counter" } ], "ProfileFunctionalities": [ { "ProfileFunctionalityID": 1271, "Profile_ID": 68, "Functionality_ID": 105, "CanInsert": false, "CanUpdate": false, "CanDelete": false } ], "ActionFull": "/budget", "HasFunctionalities": false, "model": false }, { "FunctionalityID": 112, "Name": "Config", "Action": "/config", "Icon": "build", "System_ID": 21, "FunctionalityFather_ID": null, "Active": 1, "Priority": 4, "FunctionalityChildren": [ { "FunctionalityID": 113, "Name": "Control Year Month", "Action": "/control-year-month", "Icon": "date_range", "System_ID": 21, "FunctionalityFather_ID": 112, "Active": 1, "Priority": 1, "ProfileFunctionalities": [ { "ProfileFunctionalityID": 1263, "Profile_ID": 68, "Functionality_ID": 113, "CanInsert": true, "CanUpdate": true, "CanDelete": true } ], "ActionFull": "/config/control-year-month" } ], "ProfileFunctionalities": [ { "ProfileFunctionalityID": 1262, "Profile_ID": 68, "Functionality_ID": 112, "CanInsert": false, "CanUpdate": false, "CanDelete": false } ], "ActionFull": "/config", "HasFunctionalities": true, "model": false }, { "FunctionalityID": 121, "Name": "Report", "Action": "/report", "Icon": "picture_as_pdf", "System_ID": 21, "FunctionalityFather_ID": null, "Active": 1, "Priority": 5, "FunctionalityChildren": [ { "FunctionalityID": 122, "Name": "Report 1", "Action": "/report-um", "Icon": "picture_as_pdf", "System_ID": 21, "FunctionalityFather_ID": 121, "Active": 1, "Priority": 1, "ProfileFunctionalities": [ { "ProfileFunctionalityID": 1265, "Profile_ID": 68, "Functionality_ID": 122, "CanInsert": true, "CanUpdate": true, "CanDelete": true } ], "ActionFull": "/report/report-um" }, { "FunctionalityID": 123, "Name": "Report 2", "Action": "/report-dois", "Icon": "picture_as_pdf", "System_ID": 21, "FunctionalityFather_ID": 121, "Active": 1, "Priority": 2, "ProfileFunctionalities": [ { "ProfileFunctionalityID": 1266, "Profile_ID": 68, "Functionality_ID": 123, "CanInsert": true, "CanUpdate": true, "CanDelete": true } ], "ActionFull": "/report/report-dois" }, { "FunctionalityID": 124, "Name": "Report 3", "Action": "/report-tres", "Icon": "picture_as_pdf", "System_ID": 21, "FunctionalityFather_ID": 121, "Active": 1, "Priority": 3, "ProfileFunctionalities": [ { "ProfileFunctionalityID": 1267, "Profile_ID": 68, "Functionality_ID": 124, "CanInsert": true, "CanUpdate": true, "CanDelete": true } ], "ActionFull": "/report/report-tres" } ], "ProfileFunctionalities": [ { "ProfileFunctionalityID": 1264, "Profile_ID": 68, "Functionality_ID": 121, "CanInsert": false, "CanUpdate": false, "CanDelete": false } ], "ActionFull": "/report", "HasFunctionalities": true, "model": false }, { "FunctionalityID": 125, "Name": "Profile", "Action": "/profile", "Icon": "person", "System_ID": 21, "FunctionalityFather_ID": null, "Active": 1, "Priority": 6, "FunctionalityChildren": [ { "FunctionalityID": 126, "Name": "New", "Action": "/new", "Icon": "plus_one", "System_ID": 21, "FunctionalityFather_ID": 125, "Active": 1, "Priority": 1, "ProfileFunctionalities": [ { "ProfileFunctionalityID": 1269, "Profile_ID": 68, "Functionality_ID": 126, "CanInsert": true, "CanUpdate": true, "CanDelete": true } ], "ActionFull": "/profile/new" }, { "FunctionalityID": 127, "Name": "List", "Action": "/list", "Icon": "view_list", "System_ID": 21, "FunctionalityFather_ID": 125, "Active": 1, "Priority": 2, "ProfileFunctionalities": [ { "ProfileFunctionalityID": 1270, "Profile_ID": 68, "Functionality_ID": 127, "CanInsert": true, "CanUpdate": true, "CanDelete": true } ], "ActionFull": "/profile/list" } ], "ProfileFunctionalities": [ { "ProfileFunctionalityID": 1268, "Profile_ID": 68, "Functionality_ID": 125, "CanInsert": false, "CanUpdate": false, "CanDelete": false } ], "ActionFull": "/profile", "HasFunctionalities": true, "model": false } ]

let action_full = '/budget/allocation';
   
let result = [].concat(...bigArray.map(elem => elem.FunctionalityChildren))
               .find(a => a.ActionFull == action_full); // It work only to children objects.console.log(result);

let findedInFatherAndChild = bigArray.concat(...bigArray.map(elem => elem.FunctionalityChildren)).find(a => a.ActionFull === '/budget') // This work for me, both for father and children. Thanks Mihai

Post a Comment for "Find Object In Array With Subarray Checking An Property"