【问题标题】:Filtering an array with multiple filter arrays用多个过滤器数组过滤一个数组
【发布时间】:2019-05-25 06:32:44
【问题描述】:

我正在尝试基于多个过滤器数组过滤一组项目。每个项目都有一个过滤器选择,我只需要显示与所有选定过滤器匹配的那些。

const selectedFilters = {
    color: ["Red", "Blue"],
    type: ["Shirt"],
    size: ["M"]
};

const items = [
    {
        name: "Item 1",
        filters: {
            color: ["Red", "Blue", "Black"],
            type: ["Shirt"],
            size: ["M"]
        }
    },
    {
        name: "Item 2",
        filters: {
            color: ["Red"],
            type: ["Pants"],
            size: ["M"]
        }
    }
];

这就是我一直试图解决的方法。筛选所有项目 - 对于每个不为空的筛选类别,检查所有筛选词并检查项目是否与所有项目匹配。

const filterItems = (items, selectedFilters) => {
    const filterKeys = Object.keys(selectedFilters);

    return items.filter(item => {
        return filterKeys.every(key => {

            // Ignore empty filters
            if (!selectedFilters[key].length) {
                return true;
            }

            return selectedFilters[key].every(filterWord => {
                item.filters[key].includes(filterWord);
            });
        });
    });
};

filterItems(items, selectedFilters);

返回一个空数组,应该返回一个包含“Item 1”对象的数组。

【问题讨论】:

  • 我为您的问题添加了答案。
  • 实际上,您的解决方案是完全正确的,您只是在every 回调中缺少returnreturn item.filters[key].includes(filterWord)

标签: javascript arrays filtering


【解决方案1】:

您可以创建selectedFilters 的值数组以及filters 属性值的数组。然后在selectedFilters 上使用every 检查其中的所有值是否都存在于filters 中。

const selectedFilters = {
    color: ["Red", "Blue"],
    type: ["Shirt"],
    size: ["M"]
};

const items = [
    {
        name: "Item 1",
        filters: {
            color: ["Red", "Blue", "Black"],
            type: ["Shirt"],
            size: ["M"]
        }
    },
    {
        name: "Item 2",
        filters: {
            color: ["Red"],
            type: ["Pants"],
            size: ["M"]
        }
    }
];

const filterArr = Object.values(selectedFilters).flat();

const output = items.filter(({filters}) => {
    const objFilters = Object.values(filters).flat();
    return filterArr.every(val => objFilters.includes(val));
})
console.log(output);

【讨论】:

    【解决方案2】:

    您可以使用some 来检查数组中至少包含一个元素,并且该函数需要一个 bool 返回值。

    some() 方法测试数组中是否至少有一个元素 通过提供的函数实现的测试。它返回一个 布尔值。

    const selectedFilters = {"color":["Red","Blue"],"type":["Shirt"],"size":["M"]}
    const items = [{"name":"Item 1","filters":{"color":["Red","Blue","Black"],"type":["Shirt"],"size":["M"]}},{"name":"Item 2","filters":{"color":["Red"],"type":["Pants"],"size":["M"]}}]
    
    const filterItems = (items, selectedFilters) => {
      const filterKeys = Object.keys(selectedFilters);
      return items.filter(item => {
        return filterKeys.every(key => {
          return selectedFilters[key].some(filterWord => {   //Use some
            return item.filters[key].includes(filterWord);   //Return the a bool
          });
        })
      });
    };
    
    var result = filterItems(items, selectedFilters);
    console.log(result);

    短版:

    const selectedFilters = {"color":["Red","Blue"],"type":["Shirt"],"size":["M"]};
    
    const items = [{"name":"Item 1","filters":{"color":["Red","Blue","Black"],"type":["Shirt"],"size":["M"]}},{"name":"Item 2","filters":{"color":["Red"],"type":["Pants"],"size":["M"]}}];
    
    const filterItems = (items, selectedFilters) => {
      const fkeys = Object.keys(selectedFilters);
      return items.filter(i => fkeys.every(k => selectedFilters[k].some(o => i.filters[k].includes(o))));
    };
    
    const result = filterItems(items, selectedFilters);
    console.log(result);

    【讨论】:

      【解决方案3】:

      您可以为此使用 Array.filter() 函数。这是一个非常简单有效的解决方案。

      Array.prototype.diff = function(arr2) {
          var ret = [];
          for(var i in this) {   
              if(arr2.indexOf(this[i]) > -1){
                  ret.push(this[i]);
              }
          }
          return ret;
      };
      
      var filteredArr = items.filter(function (el) {
        return el.filters.color.diff(selectedFilters.color).length > 0 &&
               el.filters.type.diff(selectedFilters.type).length > 0 &&
               el.filters.size.diff(selectedFilters.size).length > 0
      });
      

      这是工作示例..

      https://playcode.io/325371?tabs=console&script.js&output

      注意:您可以根据自己的要求更改 AND / OR 条件。

      【讨论】:

        【解决方案4】:

        有很多方法可以解决这个问题。例如,您的解决方案是正确的,但我们需要删除每个回调中的花括号 {},如下所示:

        filterWord => item.filters[key].includes(filterWord)
        

        另一种选择是使用flat() 方法将selectedFilters 转换为filterValues 数组。此方法创建一个新数组,其中所有子数组元素以递归方式连接到其中。现在,我们提取每个itemsfilters 并再次使用flat() 方法将其转换为itemFilters 数组。然后我们尝试将它们与filterValues 结合every()includes() 方法相匹配。两者都将测试数组中的所有元素是否包含每个filter 的元素。

        第三个选项与您的解决方案非常相似。在这种情况下,我们将selectedFilters 键提取到types 数组中。然后对于每一个type,我们调用some()方法结合includes()方法来测试数组中是否至少有一个元素包含在items.filters[type]中。

        这里有实现:

        const selectedFilters = {
            color: ['Red', 'Blue'],
            type: ['Shirt'],
            size: ['M']
        };
        
        const items = [
            {
                name: 'Item 1',
                filters: {
                    color: ['Red', 'Blue', 'Black'],
                    type: ['Shirt'],
                    size: ['M']
                }
            },
            {
                name: 'Item 2',
                filters: {
                    color: ['Red'],
                    type: ['Pants'],
                    size: ['M']
                }
            },
            {
                name: 'Item 3',
                filters: {
                    color: ['Green', 'Blue', 'Red'],
                    type: ['Shirt'],
                    size: ['S']
                }
            },
            {
                name: 'Item 4',
                filters: {
                    color: ['Red', 'Blue'],
                    type: ['Shirt'],
                    size: ['M']
                }
            },
        ];
        
        const filterItems = (items, selectedFilters) => {
            const filterKeys = Object.keys(selectedFilters);
            
            return items.filter(item => {
                return filterKeys.every(key => {
                    // Ignore empty filters
                    if (!selectedFilters[key].length) {
                        return true;
                    }
                    return selectedFilters[key].every(filterWord => item.filters[key].includes(filterWord));
                });
            });
        };
        
        const results = filterItems(items, selectedFilters);
        
        console.log('Your option: ');
        results.forEach(function (item, key) {
        	console.log('Name: ', item.name);
        });
        
        const filterValues = Object.values(selectedFilters).flat();
        const results2 = items.filter(({filters}) => {
            const itemFilters = Object.values(filters).flat();
            return filterValues.every(filter => itemFilters.includes(filter));
        })
        
        console.log('Second option: ');
        results2.forEach(function (item, key) {
        	console.log('Name: ', item.name);
        });
        
        
        const types = Object.keys(selectedFilters);
        const results3 = items.filter(
            item => types.every(
                type => selectedFilters[type].some(
                    filter => item.filters[type].includes(filter)
                )
            )
        );
        
        console.log('Third option: ');
        results3.forEach(function (item, key) {
        	console.log('Name: ', item.name);
        });

        【讨论】:

          【解决方案5】:
          getFilteredResult = (data)=>{
              let res = true;
              for(d in data) {
                      if(d == 'filters') {
                          let obj = data[d];  
                          for(key in obj) {
                              for(filterkey in selectedFilters) {         
                                  if(filterkey == key) {
                                      selectedFilters[filterkey].forEach(data=>{
                                           if(!obj[key].includes(data)){
                                              res=false;
                                          }
                                      })
                                  }
                              }
                          }
                      }
                  }
              return res;
          }
          items.filter((data,index,arr)=> getFilteredResult(data))
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2022-08-11
            • 2020-03-18
            • 1970-01-01
            • 2019-12-29
            • 1970-01-01
            • 1970-01-01
            • 2023-03-31
            • 1970-01-01
            相关资源
            最近更新 更多