【问题标题】:Filtering array of objects with arrays based on nested value基于嵌套值的数组过滤对象数组
【发布时间】:2016-11-17 10:56:42
【问题描述】:

我正在尝试根据一些嵌套对象过滤一个数组。我准备了一些Fiddle

输入数组如下所示:

let arrayOfElements = 
    [
        {
           "name": "a",
           "subElements": 
           [
             {"surname": 1},
             {"surname": 2}
           ]
        },
        {
           "name": "b",
           "subElements": 
           [
             {"surname": 3},
             {"surname": 1}
           ]
        },
        {
           "name": "c",
           "subElements": 
           [
             {"surname": 2},
             {"surname": 5}
           ]
        }
    ];

我希望这种情况下的输出如下所示:

let filteredArray = 
    [
        {
          "name": "a",
          "subElements": 
          [
            {"surname": 1}
          ]
        },
        {
          "name": "b",
          "subElements": 
          [
            {"surname": 1}
          ]
        }
];

我正在使用这个公式来做到这一点:

let filteredArray = arrayOfElements.filter((element) => element.subElements.some((subElement) => subElement.surname === 1));

输出几乎很好,但它返回的对象包含所有带有姓氏的对象(最好检查一下小提琴:D),而不是把它们剪掉。如何改进过滤?

【问题讨论】:

  • 您是否要根据姓氏进行分组?我的意思是同样的事情应该分组a和c,因为他们姓2。对吗?

标签: javascript filtering


【解决方案1】:

这样,您可以在数组中任意深入并过滤任何级别的元素,

arrayOfElements.map((element) => {
  return {...element, subElements: element.subElements.filter((subElement) => subElement.surname === 1)}
})

Spread operator 将扩展element,然后过滤subElements 将覆盖subElements in 元素。

【讨论】:

  • 这应该是答案,因为接受的答案没有产生预期的输出
  • 是的,这个答案更好。写入接受的答案时,对象扩展运算符不存在。
  • 这是修改原始数组
  • @Aadam 你能分享你的阵列吗? Array.map 不会修改原始数组,而是返回一个具有修改值的新数组。
  • 这个解决方案的问题是返回的元素数量与原来的相同。他们将 subElements 数组为空,因此更正方法是通过检查 subElements 的长度向结果映射添加过滤器。
【解决方案2】:

调用filter 后,需要将结果通过管道传送到map,如下所示:

let filteredArray = arrayOfElements
  .filter((element) => 
    element.subElements.some((subElement) => subElement.surname === 1))
  .map(element => {
    let newElt = Object.assign({}, element); // copies element
    return newElt.subElements.filter(subElement => subElement.surname === '1');
  });

我在这里假设您不想操纵原始数组。所以,我正在使用 Object.assign。

【讨论】:

  • 这不是只返回子元素数组,而不是过滤后的子数组的完整对象吗?
  • @WannyMiarelli 是正确的。它将返回过滤后的子数组,而不是带有过滤姓氏的完整对象。上面的代码也有错误(字符串检查而不是整数和错字surName)。
  • 这个解决方案没有产生预期的输出:jsbin.com/dunuqeyeje/edit?js,console
  • @LokeshSanapalli,在您最后一次致电filter 时,您需要将surName 更改为surname。然后它工作。那是我上面的错误。现已更正。
  • 嗨@AndrewEisenberg!感谢您的输入。现在 4 年后,我决定将接受的答案更改为使用扩展运算符的答案,因为它似乎更适合 2020 年 :) 谢谢,我希望没有难过的感觉 :)
【解决方案3】:
let filteredArray = arrayOfElements
    .filter((element) => 
        element.subElements.some((subElement) => subElement.surname === 1))
    .map(element => {
        let newElt = Object.assign({}, element); // copies element
        newElt.subElements = newElt.subElements.filter(subElement => subElement.surName === '1'); 
        return newElt;
    });

更正确

【讨论】:

    【解决方案4】:

    刚刚改进了上面的答案

    let elements = 
        [
            {
               "name": "a",
               "subElements": 
               [
                 {"surname": 1},
                 {"surname": 2}
               ]
            },
            {
               "name": "b",
               "subElements": 
               [
                 {"surname": 3},
                 {"surname": 1}
               ]
            },
            {
               "name": "c",
               "subElements": 
               [
                 {"surname": 2},
                 {"surname": 5}
               ]
            }
        ];
    var value = 1;
    
    var filteredArray = elements
    .filter(element => element.subElements
      .some(subElement => subElement.surname === value)
    )
    .map(element => {
      let n = Object.assign({}, element, {'subElements': element.subElements.filter(
        subElement => subElement.surname === value
      )})
      return n;
    })
    
    console.log(filteredArray)

    【讨论】:

      【解决方案5】:
      let filteredArray = arrayOfElements
        .filter((element) => 
          element.subElements.some((subElement) => subElement.surname == 1))
        .map(element => {
          return Object.assign({}, element, {subElements : element.subElements.filter(subElement => subElement.surname == 1)});
      
        }); 
      

      【讨论】:

      • 当您将过滤后的数组与父对象“subElement”合并时,这将给出预期的响应。
      • 这返回了预期的响应
      【解决方案6】:

      试试这个解决方案:

      data_filter = arrayOfElements.filter(function (element) {
          return element.subElements.some( function (subElement) {
              return subElement.surname === surname
          });
      });
      

      【讨论】:

      • 它不会返回准确的预期响应,而是返回找到的对象中的所有姓氏
      【解决方案7】:

      你也可以让它通用:

      逻辑

      • 查找所有不同的姓氏并遍历它们
      • 过滤每个对象以检查姓氏是否存在。如果是,请使用Object.assign 复制对象并将subElements 值设置为过滤列表。
      • 创建一个临时数组来保存所有相似的对象并将复制的对象推送到它。
      • 每次迭代不同姓氏时,将此数组推入最终数组。

      样本

      let arrayOfElements=[{name:"a",subElements:[{surname:1},{surname:2}]},{name:"b",subElements:[{surname:3},{surname:1}]},{name:"c",subElements:[{surname:2},{surname:5}]}];
       let distinct_surnames = [];
       arrayOfElements.forEach(function(el) {
         el.subElements.forEach(function(s) {
           if (distinct_surnames.indexOf(s.surname) < 0) distinct_surnames.push(s.surname)
         });
       })
      
       let result = [];
       distinct_surnames.forEach(function(sn) {
         let inter = [];
         arrayOfElements.forEach(function(el) {
           let f = el.subElements.filter(function(sub) {
             return sub.surname === sn;
           });
           if (f.length > 0) {
             let _tmp = Object.assign({}, el);
             _tmp.subElements = f;
             inter.push(_tmp);
           }
         });
         result.push(inter);
       })
       console.log(result)

      注意:箭头函数用于保持this的引用。如果你没有在函数内部使用this,你也可以使用普通函数。

      【讨论】:

        【解决方案8】:

        function display_message() {
          let arrayOfElements = [{
            "name": "a",
            "subElements": [{
              "surname": 1
            }, {
              "surname": 2
            }]
          }, {
            "name": "b",
            "subElements": [{
              "surname": 3
            }, {
              "surname": 1
            }]
          }, {
            "name": "c",
            "subElements": [{
              "surname": 2
            }, {
              "surname": 5
            }]
          }];
          // console.log(arrayOfElements);
        var surname = 1;
          let filteredArray = arrayOfElements.filter((element) => element.subElements.some((subElement) => subElement.surname === surname));
        
          for(var data in filteredArray){
            filteredArray[data].subElements = {"surname": surname};
            }
          console.log(filteredArray);
        
        }
        &lt;input type="button" onclick="display_message();" value="click"/&gt;

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2019-08-27
          • 2020-09-17
          • 1970-01-01
          • 2021-07-07
          • 2017-06-29
          • 2021-08-04
          • 2021-08-22
          相关资源
          最近更新 更多