【问题标题】:AND/OR logic with .filter()与 .filter() 的 AND/OR 逻辑
【发布时间】:2017-08-05 10:17:00
【问题描述】:

我正在尝试创建一个产品网格过滤系统。通过在 JSON 对象上调用 .filter(),我得到了我正在寻找的结果。

const filteredProducts = allProducts.filter((a) => {
  // return brown or blue products in with omnis tag
  const prodTags = a.tags;
  return (
    prodTags.includes('brown') && prodTags.includes('single-eye') && prodTags.includes('happy') ||
    prodTags.includes('brown') && prodTags.includes('single-eye') && prodTags.includes('angry') ||
    prodTags.includes('brown') && prodTags.includes('two-eyes') && prodTags.includes('happy') ||
    prodTags.includes('brown') && prodTags.includes('two-eyes') && prodTags.includes('angry') ||
    prodTags.includes('blue') && prodTags.includes('single-eye') && prodTags.includes('happy') ||
    prodTags.includes('blue') && prodTags.includes('single-eye') && prodTags.includes('angry') ||
    prodTags.includes('blue') && prodTags.includes('two-eyes') && prodTags.includes('happy') ||
    prodTags.includes('blue') && prodTags.includes('two-eyes') && prodTags.includes('angry')
  );
});

我很难想出一种方法来使这种动态化。我似乎无法创建一个可以为任意数量的标签自动生成此逻辑的函数。

我有一个看起来像这样的过滤系统(~ 是当前选定的):

-----------
Colors:
-----------
~ brown
gray
~ blue
pink


-----------
Eyes:
-----------
~ single-eye
~ two-eyes


-----------
Emotion:
-----------
~ happy
~ angry
sad

类别之间的逻辑是AND。类别值之间的逻辑是 OR。我有一个创建笛卡尔积数组的函数设置。选定的过滤器数组如下所示:

[
    ['brown', 'single-eye', 'angry'],
    ['brown', 'single-eye', 'happy'],
    ['brown', 'two-eyes', 'angry'],
    ['brown', 'two-eyes', 'happy'],
    ['blue', 'single-eye', 'angry'],
    ['blue', 'single-eye', 'happy'],
    ['blue', 'two-eyes', 'angry'],
    ['blue', 'two-eyes', 'happy']
]

这就是我卡住的地方。我似乎无法找到一种方法将这个生成的数组动态集成到 .filter() 中并使用 ||和 && 相应地。

非常感谢任何帮助。

【问题讨论】:

  • 不确定预期结果是什么?您可以在 Question 中包含输入数组吗?

标签: javascript arrays ecmascript-6 filtering


【解决方案1】:

您可以将数组与分组项一起使用并通过检查进行迭代。

var allProducts = [{ foo: 1, tags: ['abc', 'def'] }, { foo: 2, tags: ['blue', 'two-eyes', 'happy'] }],
    groups = [['brown', 'blue'], ['single-eye', 'two-eyes'], ['angry', 'happy']],
    filteredProducts = allProducts.filter(product => groups.every(group => group.some(item => product.tags.includes(item))));

console.log(filteredProducts);
.as-console-wrapper { max-height: 100% !important; top: 0; }

【讨论】:

    【解决方案2】:

    其他两个答案看起来都是正确的。除了已经建议的内容之外,我还将使用Array.every,以便该函数不依赖于每行的长度。

    const cart = [
        ['brown', 'single-eye', 'angry'],
        ['brown', 'single-eye', 'happy'],
        ['brown', 'two-eyes', 'angry'],
        ['brown', 'two-eyes', 'happy'],
        ['blue', 'single-eye', 'angry'],
        ['blue', 'single-eye', 'happy'],
        ['blue', 'two-eyes', 'angry'],
        ['blue', 'two-eyes', 'happy']
      ];
    
    const filteredProducts = allProducts.filter((a) => {
      const prodTags = a.tags;
    
      return cart.some((row) => {
        return row.every((element) => {
          return prodTags.includes(element);
        });
      });
    });
    

    【讨论】:

    • 好建议。
    • 太棒了!一个不依赖于行长的函数,正是我想要的!感谢您的小改进,并感谢@RickHitchcock 的原始解决方案。你们太棒了!
    【解决方案3】:

    预期生成的逻辑意味着数组中的任何特定行,如果导致true,将是需要计算的最后一行。我的方法是做一个for 循环,当特定行返回true 时会中断。如果true 中没有行结果,则回退到false

    var filtersArray = [
      ['brown', 'single-eye', 'angry'],
      ['brown', 'single-eye', 'happy'],
      ['brown', 'two-eyes', 'angry'],
      ['brown', 'two-eyes', 'happy'],
      ['blue', 'single-eye', 'angry'],
      ['blue', 'single-eye', 'happy'],
      ['blue', 'two-eyes', 'angry'],
      ['blue', 'two-eyes', 'happy']
    ];
    
    
    const filteredProducts = allProducts.filter((a) => {
      // return brown or blue products in with omnis tag
      const prodTags = a.tags;
    
      for (var i = 0; i < filtersArray.length; i++) {
        let color = filtersArray[i][0];
        let count = filtersArray[i][1];
        let emotion = filtersArray[i][2];
    
        if (prodTags.includes(color) && prodTags.includes(count) && prodTags.includes(emotion)) {
          return true;
        }
      }
    
      return false;
    )};
    

    【讨论】:

      【解决方案4】:

      您可以在笛卡尔积数组上使用Array.prototype.some() 以确保至少满足一个条件:

      const filteredProducts = allProducts.filter((a) => {
        const prodTags = a.tags,
              cart = [
                      ['brown', 'single-eye', 'angry'],
                      ['brown', 'single-eye', 'happy'],
                      ['brown', 'two-eyes', 'angry'],
                      ['brown', 'two-eyes', 'happy'],
                      ['blue', 'single-eye', 'angry'],
                      ['blue', 'single-eye', 'happy'],
                      ['blue', 'two-eyes', 'angry'],
                      ['blue', 'two-eyes', 'happy']
                     ];
      
        return cart.some((e) => {
          return progTags.includes(e[0]) && progTags.includes(e[1]) && progTags.includes(e[2]);
        });
      });
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多