过滤数组并比较但跳过空值

Filter array and compare but skip null values

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

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.horsepowers == null ? true : product.horsepowers === selectedOptions.horsepowers &&
product.doors == null ? true : product.doors === selectedOptions.doors

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

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

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) returns 是的,所以这行得通。

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

你可以先预处理selectedOptions然后比较:

const applicableOptions = Object.entries(selectedOptions).filter(
  ([_, value]) => value !== null && value !== undefined
);

const availableProducts = products.filter((product) =>
  applicableOptions.every(([optKey, optValue]) => product[optKey] === optValue)
);

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

  • 使用 Object#entries and Array#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);

您可以从 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);
    

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

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

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 的另一个问题...

"however, how do I skip null values, empty arrays, and undefined values if the user has not yet selected all possible options yet?"

... 并且还提供了一个通用的解决方案,上面的方法可以改成一个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; }