【问题标题】:Filter array and compare but skip null values过滤数组并比较但跳过空值
【发布时间】:2021-12-27 01:01:51
【问题描述】:

我目前正在尝试根据所选选项过滤可用产品。

const products = [{
        id: 1,
        name: 'Safari',
        horsepowers: 30,
        doors: 4,
        gear_type: 'automatic',
        wheels: 6
    },
    {
        id: 2,
        name: 'Jungle',
        horsepowers: 50,
        doors: 3,
        gear_type: 'automatic',
        wheels: 5
    },
    {
        id: 3,
        name: 'Moon',
        horsepowers: 30,
        doors: 4,
        gear_type: 'manual',
        wheels: 4
    }
]
const selectedOptions = 
{
   horsepowers: 50,
   doors: 3,
   gear_type: null,
   wheels: null
}

通常我会做类似的事情

const availableProducts = products.filter((product) => 
  product.horsepowers === selectedOptions.horsepowers &&
  product.doors === selectedOptions.doors .... etc

但是,如果用户尚未选择所有可能的选项,我该如何跳过空值、空数组和未定义值?

【问题讨论】:

  • 为什么不过滤 selectedOptions 以删除具有空值的对?然后获取并迭代其他过滤器测试的键。
  • 请添加一些不需要的值的示例。
  • 感谢您的众多回答。对大家很有帮助。

标签: javascript arrays filter conditional-statements


【解决方案1】:
selectedOptions.horsepowers == null ? true : product.horsepowers === selectedOptions.horsepowers &&
product.doors == null ? true : product.doors === selectedOptions.doors

如果要保持一致,可以在比较之前使用三元运算符检查它是否为空。

【讨论】:

    【解决方案2】:

    您可以遍历selectedOptions,而不是手动输入每个选项。那么就很简单了,在比较之前检查每个选项的值是否为空。

    let filtered = products.filter(e => {
      for(let [key, value] of Object.entries(selectedOptions))
      {
        if(value != null && e[key] != value)
          return false;
      }
      return true;
    });
    

    const products = [{
            id: 1,
            name: 'Safari',
            horsepowers: 30,
            doors: 4,
            gear_type: 'automatic',
            wheels: 6
        },
        {
            id: 2,
            name: 'Jungle',
            horsepowers: 50,
            doors: 3,
            gear_type: 'automatic',
            wheels: 5
        },
        {
            id: 3,
            name: 'Moon',
            horsepowers: 30,
            doors: 4,
            gear_type: 'manual',
            wheels: 4
        }
    ]
    
    const selectedOptions = 
    {
       horsepowers: 50,
       doors: 3,
       gear_type: null,
       wheels: null
    }
    
    let filtered = products.filter(e => {
      for(let [key, value] of Object.entries(selectedOptions))
      {
        if(value != null && e[key] != value)
          return false;
      }
      return true;
    });
    
    console.log(filtered);

    但是,如果您真的想将其写出来,我只需通过简单的布尔检查来检查该选项是否已设置。 !(null) 返回 true,所以这会起作用。

    return (!selectedOptions.horsepowers || selectedOptions.horsepowers == product.horsepowers) && ...
    

    【讨论】:

      【解决方案3】:

      您可以先预处理selectedOptions,然后进行比较:

      const applicableOptions = Object.entries(selectedOptions).filter(
        ([_, value]) => value !== null && value !== undefined
      );
      
      const availableProducts = products.filter((product) =>
        applicableOptions.every(([optKey, optValue]) => product[optKey] === optValue)
      );
      

      要使用数组进行比较,您需要更新示例,因为没有数组属性

      【讨论】:

        【解决方案4】:
        • 使用Object#entriesArray#filter,从selectedOptions 中获取具有选定值的对,用于过滤产品列表
        • 使用 Array#filterArray#every 过滤列表以确保生成的产品与上述配对匹配

        const 
          products = [ { id: 1, name: 'Safari', horsepowers: 30, doors: 4, gear_type: 'automatic', wheels: 6 }, { id: 2, name: 'Jungle', horsepowers: 50, doors: 3, gear_type: 'automatic', wheels: 5 }, { id: 3, name: 'Moon', horsepowers: 30, doors: 4, gear_type: 'manual', wheels: 4 } ],
          selectedOptions = { horsepowers: 50, doors: 3, gear_type: null, wheels: null };
        
        const filterOptions = 
          Object.entries(selectedOptions).filter(([_, value]) => value !== null);
        const selectedProducts = 
          products.filter(product =>
            filterOptions.every(([key, value]) => product[key] === value)
          );
        
        console.log(selectedProducts);

        【讨论】:

          【解决方案5】:

          您可以从selectedOptions 生成一个过滤器数组,然后过滤条目并使用它来过滤数据。

          const
              products = [{ id: 1, name: 'Safari', horsepowers: 30, doors: 4, gear_type: 'automatic', wheels: 6 }, { id: 2, name: 'Jungle', horsepowers: 50, doors: 3, gear_type: 'automatic', wheels: 5 }, { id: 3, name: 'Moon', horsepowers: 30, doors: 4, gear_type: 'manual', wheels: 4 }],
              selectedOptions = { horsepowers: 50, doors: 3, gear_type: null, wheels: null },
              filter = Object
                  .entries(selectedOptions)
                  .filter(([, v]) => v !== null),
              result = products.filter(o => filter.every(([k, v]) => o[k] === v));
          
          console.log(result);
              

          【讨论】:

            【解决方案6】:

            下一个提供的方法利用the 2nd thisArg argument of almost every available prototypal array method

            因此可以编写一个通用过滤器函数,将任何项目的属性值与selectedOptions 对象配置的相关值进行比较,该对象将作为filter 的第二个参数和过滤器函数的@ 与过滤器函数一起传递987654325@上下文...

            const selectedOptions = {
              horsepowers: 50,
              doors: 3,
              gear_type: null,
              wheels: null,
            };
            const products = [{
              id: 1,
              name: 'Safari',
              horsepowers: 30,
              doors: 4,
              gear_type: 'automatic',
              wheels: 6,
            }, {
              id: 2,
              name: 'Jungle',
              horsepowers: 50,
              doors: 3,
              gear_type: 'automatic',
              wheels: 5,
            }, {
              id: 3,
              name: 'Moon',
              horsepowers: 30,
              doors: 4,
              gear_type: 'manual',
              wheels: 4,
            }];
            
            function doItemPropertiesEqualEveryBoundSelectedOption(item) {
              return Object
                // create key value pairs from the `this` bound selected options.
                .entries(this)
                // skip/ignore selected option entries where `value` equals `null`.
                .filter(([key, value]) => value !== null)
                // execute item specific selected option validation via `every`.
                .every(([key, value]) => item[key] === value);    
            }
            console.log(
              products
                .filter(
                  doItemPropertiesEqualEveryBoundSelectedOption,
                  selectedOptions,
                )
            );
            .as-console-wrapper { min-height: 100%!important; top: 0; }

            为了回答 OP 的另一个问题...

            “但是,如果用户尚未选择所有可能的选项,我该如何跳过空值、空数组和未定义值?”

            ... 并且还提供了一个通用的解决方案,上述方法可以更改为thisArg 对象,该对象不仅具有选定的选项,而且还具有不被验证(无效)selectedOption 属性的条件...

            const products = [{
              id: 1,
              name: 'Safari',
              horsepowers: 30,
              doors: 4,
              gear_type: 'automatic',
              wheels: 6,
            }, {
              id: 2,
              name: 'Jungle',
              horsepowers: 50,
              doors: 3,
              gear_type: 'automatic',
              wheels: 5,
            }, {
              id: 3,
              name: 'Moon',
              horsepowers: 30,
              doors: 4,
              gear_type: 'manual',
              wheels: 4,
            }];
            
            const selectedOptions = {
              horsepowers: 50,
              doors: 3,
              gear_type: null,
              wheels: null,
            };
            const isInvalidValue = (value) => {
              return Array.isArray(value)
                // empty array validation.
                ? (value.length === 0)
                // undefined and null value validation.
                : (value == null)
            }
            
            function doItemPropertiesEqualEveryBoundValidOption(item) {
              const { options, isInvalidValue } = this;
              return Object
                .entries(options)
                .filter(([key, value]) => !isInvalidValue(value))
                .every(([key, value]) => item[key] === value);    
            }
            console.log(
              products
                .filter(
                  doItemPropertiesEqualEveryBoundValidOption,
                  { options: selectedOptions, isInvalidValue },
                )
            );
            .as-console-wrapper { min-height: 100%!important; top: 0; }

            【讨论】:

              猜你喜欢
              • 2017-01-28
              • 1970-01-01
              • 1970-01-01
              • 2021-11-18
              • 2018-04-01
              • 1970-01-01
              • 2020-07-03
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多