对象数组:仅返回属性匹配的对象(和子对象)

时间:2016-02-19 20:13:45

标签: javascript jquery arrays linq.js

我有一个包含几个“级别”或子级的数组。我想创建一个新的对象数组,其中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

3 个答案:

答案 0 :(得分:2)

处理递归的精心设计的函数可以使用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

答案 1 :(得分:1)

这需要递归。

更改您的代码以包含一个与此伪代码一致的函数:

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

答案 2 :(得分:1)

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

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>')