【问题标题】:Array of objects: return only objects (and children) where attribute matches对象数组:仅返回属性匹配的对象(和子对象)
【发布时间】:2016-02-19 20:13:44
【问题描述】:

我有一个包含多个“级别”或子级的数组。我想创建一个新的对象数组,其中 archived===false 以便不列出任何已归档的对象。

所以这个...

var arr = [
    {"id":1, "archived":false,"children":[
        {"id":1,"archived":true, "subs":[
            {"id":1,"archived":true},
            {"id":2,"archived":true},
            {"id":3,"archived":true}
        ]},
        {"id":2,"archived":false, "subs":[
            {"id":1,"archived":false},
            {"id":2,"archived":false},
            {"id":3,"archived":true}
        ]}
    ]},
    {"id":2, "archived":true,"children":[
        {"id":1,"archived":true, "subs":[
            {"id":1,"archived":true},
            {"id":2,"archived":true},
            {"id":3,"archived":true}
        ]},
        {"id":2,"archived":true, "subs":[
            {"id":1,"archived":true},
            {"id":2,"archived":true},
            {"id":3,"archived":true}
        ]}
    ]},
    {"id":3, "archived":false,"children":[
        {"id":1,"archived":false, "subs":[
            {"id":1,"archived":true},
            {"id":2,"archived":false},
            {"id":3,"archived":true}
        ]},
        {"id":2,"archived":false, "subs":[
            {"id":1,"archived":false},
            {"id":2,"archived":false},
            {"id":3,"archived":false}
        ]}
    ]}
];

变成……

var arr = [
    {"id":1, "archived":false,"children":[
        {"id":2,"archived":false, "subs":[
            {"id":1,"archived":false},
            {"id":2,"archived":false}
        ]}
    ]},
    {"id":3, "archived":false,"children":[
        {"id":1,"archived":false, "subs":[
            {"id":2,"archived":false}
        ]},
        {"id":2,"archived":false, "subs":[
            {"id":1,"archived":false},
            {"id":2,"archived":false},
            {"id":3,"archived":false}
        ]}
    ]}
];

我已经尝试过 map、reduce、filter 和 grep 的组合...但我可能没有正确的顺序等。我知道我可以循环遍历每个级别,但我无法做到对。

将它包含在 linq.js 可枚举数组或 jQuery 中会很棒。

Non-working Example fiddle

【问题讨论】:

  • 你查看过 Array.prototype.map 吗?
  • 我做到了,但我无法在整个“关卡”中找到正确的孩子

标签: javascript jquery arrays linq.js


【解决方案1】:

处理递归的精心设计的函数可以使使用 linq.js 执行此操作变得相当简单。这尤其不一定需要 linq.js,但它保持简单。

function isNotArchived(childrenName, childrenFilter) {
  return function (e) {
    var filtered = e.Where("!$.archived");
    if (childrenName && childrenFilter) {
      return filtered.Select(function (c) {
        var result = { id: c.id, archived: c.archived };
        result[childrenName] = $.Enumerable.From(c[childrenName])
          .Let(childrenFilter)
          .ToArray();
        return result;
      });
    }
    return filtered;
  };
}
var filtered = $.Enumerable.From(arr)
  .Let(isNotArchived("children",
    isNotArchived("subs",
      isNotArchived()
    )
  ))
  .ToArray();

fiddle

【讨论】:

  • 这真的很好,但是,代码在“子”数组之一中缺少 archived:true:jsfiddle.net/ksumarine/ed7ppmxc
  • 在排除父级时为什么要包括它们?按照您设置输入和输出的方式,父对象必须存在。如果您专门尝试搜索未在任何级别存档的任何对象,那么您需要更改您希望输出的方式。并且对于您拥有的当前结构(它必须与现有对象匹配),它就是行不通的。
  • 不,我是说您的代码输出包含一个已归档的项目,但它应该排除所有已归档的项目。
  • 哦,对不起,我误会了。我明白你的意思,它需要一些调整。
【解决方案2】:

这需要递归。

更改您的代码以包含一个按照此伪代码行工作的函数:

function filterRecursive(array, filterFunction){
    for(obj in array){
        if(obj.children){
            obj.children = filterRecursive(obj.children, filterFunction);
        }
        obj = filterFunction(obj);
    }
}

【讨论】:

  • 谢谢,但我不确定如何实现。也许我一直盯着我的所有代码看太多了。
  • @ksumarine,这不是你的错。 Gravityplanx 的答案需要说明如何 来实现它,而不仅仅是什么样的功能。
  • @Mirabilis:SO 是一种更好地了解编码实践的资源,而不是让其他人为您编写代码的地方。我的回答解释了提供的代码中缺少的内容,仍然取决于 ksumarine 来编写它以满足他自己的需要。
  • @ksumarine:诀窍是您需要在自身中调用filterRecursive,传入子数组而不是父数组。一次通过过滤器就无法完成您的要求。相反,您需要为父级别执行一次,然后为每个子数组重新调用该函数。具体来说,在提供的伪代码中,请注意第 4 行如何调用它所在的函数,但作用于子级。
  • @gravityplanx 我不是要任何人为我编写代码,但解释一下您要向我展示的内容会有所帮助。编辑:在你提供解释之前写下这个......谢谢!
【解决方案3】:

我的解决方案没有递归并假设初始对象的深度和结构是固定的:

var arr = [
  {
    "id": 1, "archived": false, "children": [
      {
        "id": 1, "archived": true, "subs": [
          {"id": 1, "archived": true},
          {"id": 2, "archived": true},
          {"id": 3, "archived": true}
        ]
      },
      {
        "id": 2, "archived": false, "subs": [
          {"id": 1, "archived": false},
          {"id": 2, "archived": false},
          {"id": 3, "archived": true}
        ]
      }
    ]
  },
  {
    "id": 2, "archived": true, "children": [
      {
        "id": 1, "archived": true, "subs": [
          {"id": 1, "archived": true},
          {"id": 2, "archived": true},
          {"id": 3, "archived": true}
        ]
      },
      {
        "id": 2, "archived": true, "subs": [
          {"id": 1, "archived": true},
          {"id": 2, "archived": true},
          {"id": 3, "archived": true}
        ]
      }
    ]
  },
  {
    "id": 3, "archived": false, "children": [
      {
        "id": 1, "archived": false, "subs": [
          {"id": 1, "archived": true},
          {"id": 2, "archived": false},
          {"id": 3, "archived": true}
        ]
      },
      {
        "id": 2, "archived": false, "subs": [
          {"id": 1, "archived": false},
          {"id": 2, "archived": false},
          {"id": 3, "archived": false}
        ]
      }
    ]
  }
];

function checkChildrensForFalse(elements) {
  var retVal = [];
  for (var eleChildIndex in elements) {
    if (elements[eleChildIndex].archived == false) {
      var tmpObj = {
        'id': elements[eleChildIndex].id,
        'archived': elements[eleChildIndex].archived,
        'subs': []
      }
      for (var eleSubIndex in elements[eleChildIndex].subs) {
        if (elements[eleChildIndex].subs[eleSubIndex].archived == false) {
          tmpObj.subs.push(elements[eleChildIndex].subs[eleSubIndex]);
        }
      }
      if (tmpObj.subs !== []) {
        retVal.push(tmpObj);
      }
    }
  }
  return retVal;
}

arr = arr.map(function (currentValue, index, array) {
  if (currentValue.archived == false) {
    var ele = checkChildrensForFalse(currentValue.children);
    if (ele !== []) {
      return {'id': currentValue.id, 'archived': currentValue.archived, 'children': ele};
    }
  } else {
    return null;
  }
}).filter(function (item) {
  return item != null
});

/**********
         * The result formatted is:
        var result = [{
            "id": 1, "archived": false,"children": [{
                "id": 2, "archived": false, "subs": [
                    {"id": 1, "archived": false}, {"id": 2, "archived": false}]
            }]
        }, {"id": 3, "archived": false, "children": [
            {"id": 1, "archived": false, "subs": [{"id": 2, "archived": false}]},
            {"id": 2, "archived": false, "subs": [{"id": 1, "archived": false}, {"id": 2, "archived": false}, {"id": 3, "archived": false}]
            }]
        }];
         */
document.write('<p>' + JSON.stringify(arr) + '</p>')

【讨论】:

    猜你喜欢
    • 2018-10-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-09-23
    • 1970-01-01
    • 2022-01-01
    • 2015-07-06
    相关资源
    最近更新 更多