【问题标题】:filter array recursively looking for parents过滤数组递归寻找父母
【发布时间】:2016-10-12 18:17:19
【问题描述】:

我有一个这样的数组:

[
    {"id":"one","name":"school", "selected": false, "children":[
      {"id":"1","name":"school", "selected": false},
      {"id":"2","name":"student", "selected": true},
      {"id":"3","name":"teacher", "selected": false}
      ]},
      {"name":"two","name":"school", "selected": false, "children":[
      {"id":"1","name":"school", "selected": true},
      {"id":"3","name":"teacher", "selected": false}
      ]},
      {"name":"three","name":"school", "selected": true, "children":[
      {"id":"1","name":"school", "selected": false},
      {"id":"2","name":"student", "selected": false}
      ]}
  ]

如何过滤该数组以仅获取字段选择为 true 的对象的名称?

输出应该是对象名称的数组:

[student, school, school]

我用 lodash 试过这个:

_.filter(array, {selected: true}).map(function (division) {
            return array.name;
        });

但这总是返回根对象,而不是子对象中的对象。

【问题讨论】:

  • 你可以使用基本的 for 循环
  • 请注意:children是child的复数形式。
  • @sabithpocker 或儿童

标签: javascript arrays algorithm filter lodash


【解决方案1】:

您可以迭代并查看想要的属性selected 是否为true,推送到结果,如果有子项,则迭代子项。

这适用于Array#forEach

var data = [{ "id": "one", "name": "school", "selected": false, "children": [{ "id": "1", "name": "school", "selected": false }, { "id": "2", "name": "student", "selected": true }, { "id": "3", "name": "teacher", "selected": false }] }, { "name": "two", "name": "school", "selected": false, "children": [{ "id": "1", "name": "school", "selected": true }, { "id": "3", "name": "teacher", "selected": false }] }, { "name": "three", "name": "school", "selected": true, "children": [{ "id": "1", "name": "school", "selected": false }, { "id": "2", "name": "student", "selected": false }] }],
    result = [];

data.forEach(function iter(o) {
    o.selected && result.push(o.name);
    (o.children || []).forEach(iter);
});
  
console.log(result);

与 lodash _.forEach 相同

var data = [{ "id": "one", "name": "school", "selected": false, "children": [{ "id": "1", "name": "school", "selected": false }, { "id": "2", "name": "student", "selected": true }, { "id": "3", "name": "teacher", "selected": false }] }, { "name": "two", "name": "school", "selected": false, "children": [{ "id": "1", "name": "school", "selected": true }, { "id": "3", "name": "teacher", "selected": false }] }, { "name": "three", "name": "school", "selected": true, "children": [{ "id": "1", "name": "school", "selected": false }, { "id": "2", "name": "student", "selected": false }] }],
    result = [];

_.forEach(data, function iter(o) {
    o.selected && result.push(o.name);
    _.forEach(o.children, iter);
});
  
console.log(result);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.15.0/lodash.min.js"></script>

带有Array#reduce的版本。

var data = [{ "id": "one", "name": "school", "selected": false, "children": [{ "id": "1", "name": "school", "selected": false }, { "id": "2", "name": "student", "selected": true }, { "id": "3", "name": "teacher", "selected": false }] }, { "name": "two", "name": "school", "selected": false, "children": [{ "id": "1", "name": "school", "selected": true }, { "id": "3", "name": "teacher", "selected": false }] }, { "name": "three", "name": "school", "selected": true, "children": [{ "id": "1", "name": "school", "selected": false }, { "id": "2", "name": "student", "selected": false }] }],
    result = data.reduce(function iter(r, o) {
        o.selected && r.push(o.name);
        return (o.children || []).reduce(iter, r);
    }, []);
  
console.log(result);

还有一个带有 lodash _.reduce 的版本。

var data = [{ "id": "one", "name": "school", "selected": false, "children": [{ "id": "1", "name": "school", "selected": false }, { "id": "2", "name": "student", "selected": true }, { "id": "3", "name": "teacher", "selected": false }] }, { "name": "two", "name": "school", "selected": false, "children": [{ "id": "1", "name": "school", "selected": true }, { "id": "3", "name": "teacher", "selected": false }] }, { "name": "three", "name": "school", "selected": true, "children": [{ "id": "1", "name": "school", "selected": false }, { "id": "2", "name": "student", "selected": false }] }],
    result = _.reduce(data, function iter(r, o) {
        o.selected && r.push(o.name);
        return _.reduce(o.children, iter, r);
    }, []);
  
console.log(result);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.15.0/lodash.min.js"></script>

【讨论】:

  • 让我试试
【解决方案2】:
array
   .reduce((a, i) => [...a, i, ...i.childs], [])//flatten array
   .filter(i => i.selected)//filter with selected===true
   .map(i => i.name));//map to name

console.log([{
  "id": "one",
  "name": "school",
  "selected": false,
  "childs": [{
    "id": "1",
    "name": "school",
    "selected": false
  }, {
    "id": "2",
    "name": "student",
    "selected": true
  }, {
    "id": "3",
    "name": "teacher",
    "selected": false
  }]
}, {
  "name": "two",
  "name": "school",
  "selected": false,
  "childs": [{
    "id": "1",
    "name": "school",
    "selected": true
  }, {
    "id": "3",
    "name": "teacher",
    "selected": false
  }]
}, {
  "name": "three",
  "name": "school",
  "selected": true,
  "childs": [{
    "id": "1",
    "name": "school",
    "selected": false
  }, {
    "id": "2",
    "name": "student",
    "selected": false
  }]
}].reduce((a, i) => [...a, i, ...i.childs], []).filter(i => i.selected).map(i => i.name));

【讨论】:

    【解决方案3】:

    您可以使用这种函数式编程风格的 ES6 解决方案:

    function sel(array) {
        return (array || []).reduce ( (acc, o) => 
            (o.selected ? acc.concat(o.name) : acc).concat(sel(o.childs)), [] );
    }
    

      
    function sel(array) {
        return (array || []).reduce ( (acc, o) => 
            (o.selected ? acc.concat(o.name) : acc).concat(sel(o.childs)), [] );
    }
    // Sample data
    var array = [
        {"id":"one","name":"school", "selected": false, "childs":[
          {"id":"1","name":"school", "selected": false},
          {"id":"2","name":"student", "selected": true},
          {"id":"3","name":"teacher", "selected": false}
          ]},
          {"name":"two","name":"school", "selected": false, "childs":[
          {"id":"1","name":"school", "selected": true},
          {"id":"3","name":"teacher", "selected": false}
          ]},
          {"name":"three","name":"school", "selected": true, "childs":[
          {"id":"1","name":"school", "selected": false},
          {"id":"2","name":"student", "selected": false}
          ]}
      ];
    // Extract
    var result = sel(array);
    // Ooutput result
    console.log(result);

    【讨论】:

      【解决方案4】:

      您可以使用Array.prototype.map()Array.prototype.filter()

      var arr = [{
        "id": "one",
        "name": "school",
        "selected": false,
        "childs": [{
          "id": "1",
          "name": "school",
          "selected": false
        }, {
          "id": "2",
          "name": "student",
          "selected": true
        }, {
          "id": "3",
          "name": "teacher",
          "selected": false
        }]
      }, {
        "name": "two",
        "name": "school",
        "selected": false,
        "childs": [{
          "id": "1",
          "name": "school",
          "selected": true
        }, {
          "id": "3",
          "name": "teacher",
          "selected": false
        }]
      }, {
        "name": "three",
        "name": "school",
        "selected": true,
        "childs": [{
          "id": "1",
          "name": "school",
          "selected": false
        }, {
          "id": "2",
          "name": "student",
          "selected": false
        }]
      }];
      
      var res = arr.map(el =>
        (el.selected && el || el.childs.filter(child =>
          child.selected
        )[0]).name
      );
      
      console.log(res);

      【讨论】:

      • 感谢您的解决方案,非常棒
      【解决方案5】:

      好吧,您应该考虑您尝试构建的脚本的复杂性。这是一种嵌套线性算法(请参阅https://en.wikipedia.org/wiki/Linear_search),因为您必须接触数组中的每个元素才能使用selected 元素创建新的数据结构,如果数组大小增加,这可能会非常慢。

      您可能想要做的是修改切换selected 属性的方法,并将该“选定”对象复制到新的selectedElements 数组。

      但是,如果您需要按照您的要求进行操作,并且您只想要唯一的结果,请查看以下内容:

      var data = [
        {"id":"one","name":"school", "selected": false, "childs":[
          {"id":"1","name":"school", "selected": false},
          {"id":"2","name":"student", "selected": true},
          {"id":"3","name":"teacher", "selected": false}
        ]},
        {"name":"two","name":"school", "selected": false, "childs":[
          {"id":"1","name":"school", "selected": true},
          {"id":"3","name":"teacher", "selected": false}
        ]},
        {"name":"three","name":"school", "selected": true, "childs":[
          {"id":"1","name":"school", "selected": false},
          {"id":"2","name":"student", "selected": false}
        ]}
      ],
          selectedElements = [];
      
      data.map(function(row, i){
        if (row.selected) {
          if (selectedElements.indexOf(row.name) == - 1)
            selectedElements.push(row.name);
        }
        else{
          row.childs.map(function(childRow, ii) {
            if (childRow.selected) {
              if (selectedElements.indexOf(childRow.name) == - 1)
                selectedElements.push(childRow.name);
              }
          })
        }
      });
      
      console.log(selectedElements);

      【讨论】:

        【解决方案6】:

        在你的 lodash _.filter 之前添加一行

        array = _.flatten(array.map(x => [x].concat(x.childs)))
        

        所以它需要childs

        【讨论】:

          【解决方案7】:

          带有箭头函数的经典递归解决方案

          var result = [];
          var recursiveSearch = arr => {
            if (Array.isArray(arr)) {
              arr.forEach(x => {
              if (x.selected === true) result.push(x.name);
              if (Array.isArray(x.childs)) recursiveSearch(x.childs);
              });
            }
          }
          recursiveSearch(data);
          console.log (result);
          

          【讨论】:

            猜你喜欢
            • 2021-08-10
            • 1970-01-01
            • 2021-12-15
            • 1970-01-01
            • 1970-01-01
            • 2016-11-03
            • 2014-06-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多