如何使用 'reduce' 函数筛选和显示购物车中的产品

How to use 'reduce' function to filter and display products in cart

我正在尝试用 Javascript 训练自己,但对 reduce 有点困惑,希望能得到一些指导以帮助我理解它。我已经做了很多研究并且已经到了需要一些不仅仅是谷歌搜索的清晰度的阶段。所以这是我的基本示例代码..

ID 是购物车 ID,产品是商店中的产品

      const ids = [4, 3, 1];
      const products = [
        { id: 1, product: "Product 1" },
        { id: 2, product: "Product 2" },
        { id: 3, product: "Product 3" },
        { id: 4, product: "Product 4" },
        { id: 5, product: "Product 5" },
        { id: 6, product: "Product 6" },
        { id: 7, product: "Product 7" },
      ];


我需要显示购物车中的产品,所以我选择了 3 个选项 for 循环、mapfilter 最后是 reduce


FOR 循环

      // SOLUTION WITH FOR LOOP
      const selectedProducts = [];
      for (id of ids) {
        const selectedProduct = products.filter((product) => product.id === id);
        selectedProducts.push(selectedProduct);
      }
      console.log("selectedProducts", selectedProducts);

问题1 : 目前我只有7个产品。但是在实际的商店中会有数千种产品。因此,为每个 id 过滤数千种产品是一个好主意。有更好的方法吗?


MAP 和 FILTER

      // SOLUTION WITH MAP
      const mappedProducts = ids.map((id) => {
        const [obj] = products.filter((product) => product.id === id);
        return obj;
      });
      console.log("mappedProducts", mappedProducts);

问题 2:当过滤器创建一个数组时,我得到了一个数组数组,不得不解构数组和 return 对象。有没有更好的方法可以直接 destructure/pass 对象而无需显式声明 return.


减少

      // SOLUTION WITH REDUCE
      const initialArray = [];
      const reducedProducts = products.reduce(function (acc, product) {
        const productId = product.id;
        if (ids.includes(product.id)) acc.push(product);
        return acc;
      }, initialArray);

      console.log("reducedProducts", reducedProducts);
      console.log("initialArray", initialArray);

问题 3:我对 reduce 做错了什么?

这是我第一次使用 reduce,我确定我在这里做错了。因为 reduce 应该比 formap-[=18= 更紧凑] 组合,但在我的情况下似乎是相反的。我还认为减少 initialValue 不会发生突变。但就我而言,它正在发生变异。

如有任何帮助和建议,我们将不胜感激。

So is filtering thousands of products for each id a good idea. Is there a better way to do this?

products数组中,通过将其重组为对象或ID索引的地图来方便查找,因此您只需使用普通括号表示法或.get即可获得匹配的对象(O(1)).

const ids = [4, 3, 1];
const products = [
  { id: 1, product: "Product 1" },
  { id: 2, product: "Product 2" },
  { id: 3, product: "Product 3" },
  { id: 4, product: "Product 4" },
  { id: 5, product: "Product 5" },
  { id: 6, product: "Product 6" },
  { id: 7, product: "Product 7" },
];
const productsById = Object.fromEntries(products.map(
  obj => [obj.id, obj]
));
const result = ids.map(id => productsById[id]);
console.log(result);

Is there a better way where I could directly destructure/pass the object without explicitly declaring return.

您可以 .find 相反,return 是匹配对象而不是 return 数组 - 但这仍然是一个 O(n ^ 2) 过程。通过 ID 索引每个产品更好。

as reduce is supposed to be more compact than the for and map-filter combination but in my case it seems to be the opposite. Also I thought that with reduce the initialValue does not get mutated. But in my case it is getting mutated.

一点也不 - .reduce,当不在适当的情况下使用时,确实比更多标准循环更冗长,如您所见。参见 this video

Also I thought that with reduce the initialValue does not get mutated.

当然可以,如果初始值是一个对象(而不是原始值)——对象可以被改变。如果你改变累加器参数和 return 它,下一次迭代(以及下一次和最终的 return 值)是同一个对象。

仅供参考,几个具有 high-order 函数的示例:

减少

products.reduce((acc, product) => {
    if (ids.includes(product.id)) acc.push(product);
    return acc;
}, []);

过滤器

products.filter((product) => ids.includes(product.id));
// or with destructuring 
products.filter(({ id }) => ids.includes(id));

地图和平面

products.map((product) => (ids.includes(product.id)) ? product : []).flat();

flatMap

products.flatMap((product) => (ids.includes(product.id)) ? product : []);