【问题标题】:Javascript nested filters in Array of arrays数组数组中的Javascript嵌套过滤器
【发布时间】:2016-10-28 14:28:14
【问题描述】:

我有一个这样格式的对象数组:

var full_list = [
        {
            "pid": 1,
            "items":[
                {"item_id": '9'},
                {"item_id": '10'},
                {"item_id": '12'}
            ]
        },
        {
            "pid": 2,
            "items":[
                {"item_id": '33'},
                {"item_id": '22'},
                {"item_id": '65'}
            ]
        }...
    ];

我有一个 tmp 数组,它由完整数组中的对象组成:

 var tmp_list =  [
        {
            "pid": 2,
            "items":[
                {"item_id": '33'},
                {"item_id": '22'},
                {"item_id": '65'}
            ]
        }, {....}

我想从完整列表中过滤掉至少有一个 selectedIDs 值出现在对象的项目的 id 数组中的对象

var selectedIDs = {'1', '9', '45', ....};

然后将它们添加到 tmp 列表中。

我尝试使用过滤器,但未能完全弄清楚。

谢谢。

selectedIDs.forEach(function(id) {
                var tmp = full_list.filter(function (obj) {
                            obj.items.forEach(function (item) {
                                if (item.id === id) {
                                    console.log('found');
                                }
                            });
                        });
                        tmp_list.push(tmp);
                 });

【问题讨论】:

  • 您可以选择使用 lodash 等库吗?诸如此类的问题已经很好地解决了。
  • 临时列表中是否可能已经存在一些?如果是这样,当前的答案会产生重复

标签: javascript arrays filter


【解决方案1】:

首先,你问题中的这一行是错误的

var selectedIDs = {'1', '9', '45', ....};

您不能使用{} 声明数组。而是使用[]

对于您的问题,您可以使用 Array#filterArray#some 方法使用 纯函数方法 来获得您想要的结果,如下所示:

var full_list = [
  {
    "pid": 1,
    "items":[
      {"item_id": '9'},
      {"item_id": '10'},
      {"item_id": '12'}
    ]
  },
  {
    "pid": 2,
    "items":[
      {"item_id": '33'},
      {"item_id": '22'},
      {"item_id": '67'}
    ]
  },
  {
    "pid": 9,
    "items":[
      {"item_id": '33'},
      {"item_id": '22'},
      {"item_id": '65'}
    ]
  },
  {
    "pid": 7,
    "items":[
      {"item_id": '7'},
      {"item_id": '22'},
      {"item_id": '65'}
    ]
  }
];

var tmp_list = [
  {
    "pid": 2,
    "items":[
      {"item_id": '7'},
      {"item_id": '22'},
      {"item_id": '65'}
    ]
  }
];


function filterResult (selectedItems) {
  return full_list.filter(function (process) {
    return process.items.some(function(item){
      return selectedItems.indexOf(item.item_id) > -1;
    });
  });
}

var selectedItems = ['9', '7', '22', '10'];

tmp_list = tmp_list.concat(filterResult(selectedItems))

console.log(tmp_list);


function flattenResults(list, selections) {
  return list.reduce(function (accumulator, current) {
    var res = current.items.filter(function(item){
      return (selections.indexOf(item.item_id) > -1 
              && checkIfAlreadyExist());
              
      function checkIfAlreadyExist () {
        return accumulator.every(function (k) {
          return k.item_id !== item.item_id;
        });
      }        
    });   

    return accumulator.concat(res);
  }, []);
}

console.log(flattenResults(full_list, selectedItems));

【讨论】:

  • 老实说,我不明白那些嵌套的'return',但它完美地工作。谢谢。
  • 要了解它们,请参阅 Array.filterArray.some 的 MDN 文档:developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
  • @badigard:另外,如果解决方案适合您,请接受它,这样其他人就不必进一步探索相同/相似问题的解决方案
  • 完成。另一个小问题:如何修改这段代码,让它返回找到的 {item_id: 'x'} 对象?
  • 您的意思是仅列出找到的{item_id: 'x'} 对象,而不是包含pid, items 的整个对象吗?
【解决方案2】:

你可以这样做;

var full_list = [
        {
            "pid": 1,
            "items":[
                {"item_id": '9'},
                {"item_id": '10'},
                {"item_id": '12'}
            ]
        },
        {
            "pid": 2,
            "items":[
                {"item_id": '33'},
                {"item_id": '22'},
                {"item_id": '65'}
            ]
        }
],
  selectedIDs = ['1', '9', '45'],
     tempList = [];
tempList.push(full_list.filter(f => f.items.some(o => selectedIDs.includes(o.item_id))));
console.log(tempList);

【讨论】:

    【解决方案3】:

    您可以为 selectedID 使用哈希表并使用它进行快速过滤。

    var full_list = [{ "pid": 1, "items": [{ "item_id": '9' }, { "item_id": '10' }, { "item_id": '12' }] }, { "pid": 2, "items": [{ "item_id": '33' }, { "item_id": '22' }, { "item_id": '65' }] }],
        tmp_list,
        selectedIDs = ['1', '9', '45'],
        selected = Object.create(null);
    
    selectedIDs.forEach(function (a) {
        selected[a] = true;
    });
    
    tmp_list = full_list.filter(function (a) {
        return !a.items.some(function (b) {
            return selected[b.item_id];
        });
    });
    
    console.log(tmp_list);

    ES6

    var full_list = [{ "pid": 1, "items": [{ "item_id": '9' }, { "item_id": '10' }, { "item_id": '12' }] }, { "pid": 2, "items": [{ "item_id": '33' }, { "item_id": '22' }, { "item_id": '65' }] }],
        tmp_list,
        selectedIDs = ['1', '9', '45'],
        selected = Object.create(null);
    
    selectedIDs.forEach(a => selected[a] = true);
    tmp_list = full_list.filter(a => !a.items.some(b=> selected[b.item_id]));
    
    console.log(tmp_list);

    【讨论】:

    • 你弄错了。您必须检查 item_id 是否在 selectedIDs
    • 我使用了一个哈希表selected,检查出现在这里:!a.items.some(function (b) { return selected[b.item_id]; });
    • 如果它返回正确的答案,那将是最好的答案。但没有选定的 id 在返回值中
    • 抱歉,这是不对的,它应该在item_id 出现在selectedIDs 中的一些item_id 处过滤out
    【解决方案4】:
    array1
    array2
    
    array1.filter(el=>{
       return array2.filter(el2=>{
              return el.id == el2.id
         })
    })
    

    它将采用 array1 并针对第二个运行它...对于每个值。

    【讨论】:

      【解决方案5】:

      我认为这可能是一个解决方案。

      var full_list = [
        { 
          "pid": 1, 
          "items": [
          { "item_id": '9' }, 
          { "item_id": '10' }, 
          { "item_id": '12' }
        ]
      }, {
        "pid": 2,
        "items": [{
          "item_id": '33'
        }, {
          "item_id": '22'
        }, {
          "item_id": '65'
        }]
      }];
      
      var selectedIDs = ['33', '3'];
      var tempList = [];
      
      full_list
        .filter(item => 
          item.items
            .some(i => selectedIDs.indexOf(i.item_id) != -1)
         ).forEach(item => tempList.push(item));
      console.log(tempList)

      【讨论】:

        【解决方案6】:

        审视你的工作 1.没有什么比market更重要了

        obj.items.forEach(function (item) { if (item.item_id === id) { console.log('found'); return true; } return false;
        });

        【讨论】:

        • forEach 返回到哪里?
        【解决方案7】:

        Spread operator 应该简化一些代码:

        var full_list = [
          { 
            "pid": 1, 
            "items": [
            { "item_id": '9' }, 
            { "item_id": '10' }, 
            { "item_id": '12' }
          ]
        }, {
          "pid": 2,
          "items": [{
            "item_id": '33'
          }, {
            "item_id": '22'
          }, {
            "item_id": '65'
          }]
        }];
        
        var selectedIDs = ['65', '6'];
        var tempList = [];
        
        tempList = [...tempList, 
                    ...full_list.filter(item => item.items.some(i => selectedIDs.includes(i.item_id)))
                   ];
        
        console.log(tempList);

        【讨论】:

        • @mortezaT 为什么是多余的?有必要将两个列表解构为新列表。我认为它等同于使用 Array.concat() 方法的方法,但是使用这个 new 运算符,这使得它更具可读性,除非对我来说。 =)
        • 以上都不会附加到tempList
        • 我不明白你! OP 说:“我想从完整列表中过滤掉至少一个 selectedIDs 值出现在对象的项目的 id 数组中的对象,然后将它们添加到 tmp 列表中。”这正是我正在做的......
        • and then add them to the tmp list.的确切部分
        • 那么tmp_list 的例子没有意义。
        猜你喜欢
        • 2022-08-19
        • 2022-08-17
        • 1970-01-01
        • 2020-08-25
        • 1970-01-01
        • 1970-01-01
        • 2019-05-24
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多