2
\$\begingroup\$

I have the following function, which I believe could be improved with .

        function findSelectedInList(list){
        for(var i=0;i<=list.length;i++){                
            var currentItem = list[i];
            if(currentItem.selected === "selected"){
                return currentItem;                    
            }                
            var selectedNode = findSelectedInList(currentItem.children)
            if(selectedNode){
                return selectedNode;
            }                
        }
        return void 0;
    }

Here are some sample inputs:

    var treeList = [ { "roleName": "User", 
                   "roleId": "role1", 
                   "children": [ { "roleName": "subUser1", "roleId": "role11", "children": [], "selected": "selected" }]
                 }];


    var treeList2 = [ { "roleName": "User", "roleId": "role1", "children": [],"selected":"selected"}];
\$\endgroup\$
  • 2
    \$\begingroup\$ Something like return (currentItem.selected === "selected") || findSelectedInList(currentItem.children) would have fewer variables and "look" more recursive. \$\endgroup\$ – Barry Carter Nov 8 '17 at 13:48
  • \$\begingroup\$ Can only one item in the tree have selected set? If not, may any item with selected set be returned? \$\endgroup\$ – Gerrit0 Nov 8 '17 at 23:55
  • \$\begingroup\$ @Gerrit0 only one item can be selected. I am writing a utility class for this github.com/eu81273/angular.treeview \$\endgroup\$ – Sarawut Positwinyu Nov 9 '17 at 3:57
3
\$\begingroup\$

Initially, I considered suggesting using Array.filter() but then that wouldn't allow breaking out of the loop once a selected item was found.

One approach is to use Array.some() or Array.find() (and disregard the return value) with a ternary operator. A variable can be initialized as the first line, then the .some() callback returns the result of setting that variable to either the current item if it is selected, otherwise the return value of the recursive call.

function findSelectedInList(list) {
  var selected;
  list.some(function(currentItem) {
    return selected = currentItem.selected === "selected" ? currentItem : findSelectedInList(currentItem.children);
  });
  return selected;
}

And one could use features like arrow functions and the let keyword), to condense it slightly:

function findSelectedInList(list){
  let selected;
  list.some((currentItem) => selected = currentItem.selected === "selected" ? currentItem : findSelectedInList(currentItem.children));
  return selected;
}

To see this demonstrated, expand the snippet below.

var treeList = [{
  "roleName": "User",
  "roleId": "role1",
  "children": [{
    "roleName": "subUser1",
    "roleId": "role11",
    "children": [],
    "selected": "selected"
  }]
}];


var treeList2 = [{
  "roleName": "User",
  "roleId": "role1",
  "children": [],
  "selected": "selected"
}];
var treeList3 = [{
  "roleName": "User",
  "roleId": "role1",
  "children": []
}];

function findSelectedInList(list) {
  var selected;
  list.some(function(currentItem) {
    return selected = currentItem.selected === "selected" ? currentItem : findSelectedInList(currentItem.children);
  });
  return selected;
}
console.log('treeList: ', findSelectedInList(treeList));
console.log('treeList2: ', findSelectedInList(treeList2));
console.log('treeList3: ', findSelectedInList(treeList3));

I know it doesn't really cover the find or some methods, but these functional JS exercises are a good thing to go through.

\$\endgroup\$
  • \$\begingroup\$ Cool - perhaps you were notified but I just updated my response to contain more information about other functional methods on the Array prototype. \$\endgroup\$ – Sᴀᴍ Onᴇᴌᴀ Nov 10 '17 at 14:30

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.