【问题标题】:Using map with reduce in javascript to filter objects in an array在javascript中使用map和reduce来过滤数组中的对象
【发布时间】:2019-02-27 05:36:32
【问题描述】:

freecodecamp有一个问题,详情如下:

要求:
创建一个函数,查看对象数组(第一个参数)并返回一个包含匹配名称和值对的所有对象的数组(第二个参数)。

例如,如果第一个参数是 [{ first: "Romeo", last: "Montague" }, { first: "Mercutio", last: null }, { first: "Tybalt", last: "Capulet" }],第二个参数是 { last: "Capulet" },那么你必须从数组中返回第三个对象(第一个参数),因为它包含名称和它的值,作为第二个参数传递。

预期结果:

whatIsInAName([{ first: "Romeo", last: "Montague" }, { first: "Mercutio", last: null }, { first: "Tybalt", last: "Capulet" }], { last: "Capulet" }) should return [{ first: "Tybalt", last: "Capulet" }].

whatIsInAName([{ "apple": 1, "bat": 2 }, { "bat": 2 }, { "apple": 1, "bat": 2, "cookie": 2 }], { "apple": 1, "bat": 2 }) should return [{ "apple": 1, "bat": 2 }, { "apple": 1, "bat": 2, "cookie": 2 }].

whatIsInAName([{ "apple": 1, "bat": 2 }, { "apple": 1 }, { "apple": 1, "bat": 2, "cookie": 2 }], { "apple": 1, "cookie": 2 }) should return [{ "apple": 1, "bat": 2, "cookie": 2 }].

whatIsInAName([{ "apple": 1, "bat": 2 }, { "apple": 1 }, { "apple": 1, "bat": 2, "cookie": 2 }, { "bat":2 }], { "apple": 1, "bat": 2 }) should return [{ "apple": 1, "bat": 2 }, { "apple": 1, "bat": 2, "cookie":2 }].

根据网站,有这样的解决方案:

function whatIsInAName(collection, source) {
  var srcKeys = Object.keys(source);

  // filter the collection
  return collection.filter(function (obj) {
    return srcKeys
      .map(function(key) {
        return obj.hasOwnProperty(key) && obj[key] === source[key];
      })
      .reduce(function(a, b) {
        return a && b;
      });
  });
}

// test here
whatIsInAName([{ first: "Romeo", last: "Montague" }, { first: "Mercutio", last: null }, { first: "Tybalt", last: "Capulet" }], { last: "Capulet" });

在这个解决方案中,有一点我不是很了解,那就是 map 函数的返回值。

之前,在我的预期中,map 函数会循环遍历所有的键值对来检查它是否匹配,并返回一个布尔值的数组,例如 [{true, false}, {false, false }] 等,并将布尔值传递给 reduce 函数。

但是,当我使用以下脚本测试地图功能时:

var source = { last: "Capulet" };
var collection = [{ first: "Romeo", last: "Montague" }, { first: "Mercutio", last: null }, { first: "Tybalt", last: "Capulet" }];
var srcKeys = Object.keys({ last: "Capulet" });

collection.filter(function(obj){
  return srcKeys.map(function(key){
    return obj.hasOwnProperty(key) && obj[key] === source[key];
  })
})

而回报是这样的

(3) [{…}, {…}, {…}]
 0: {first: "Romeo", last: "Montague"}
 1: {first: "Mercutio", last: null}
 2: {first: "Tybalt", last: "Capulet"}
 length: 3
  __proto__: Array(0)

在这种情况下,我有两个问题:

  1. 在 map 函数中,它创建一个新数组,其中包含在调用数组中的每个元素上调用提供的函数的结果。在这种情况下,由于我们只想返回匹配条件的元素,为什么它不返回布尔值或只返回匹配值的元素,而是返回所有值? 还是我对映射函数的理解有误?

  2. 在map函数之后的reduce函数中,如何将映射的布尔值转换为单个布尔值,指示是否所有srcKeys都通过了上面检查的条件?比如这种情况下,reduce函数是不是简单地把map的返回值拿来做进一步的计算?

非常感谢您提前提供的帮助!

【问题讨论】:

  • 提示:绝对不需要map这个函数。
  • 在示例 1 中,map 函数的返回值是一个 true/false 值数组,具体取决于当前对象是否通过了每个测试。然后,reduce 函数将所有这些真/假值与在一起,产生真(是的,这个元素通过了所有条件)或假(它失败了一个或多个)。 .filter 函数对最终的布尔值进行操作。在您的测试中,您看到的是 .filter 操作的输出,而不是 .map
  • 替换上一条评论的最后一句。在您的测试中,.filter 内部的函数返回一个真/假值数组,而不是在逻辑上将它们转换为单个真/假值(这是 .reduce 所做的)
  • @James 谢谢!我可以澄清一下,这意味着在这种情况下,虽然 map 函数没有在控制台日志中返回一个带有布尔值的数组,但返回的结果已经有一个内部带有布尔值的隐式数组,并且可以进一步与 reduce 一起使用?跨度>

标签: javascript filter mapping reduce


【解决方案1】:

正如我所说,函数map 不是必需的。

您可以使用函数filter 和函数every 来过滤那些与键值对对象(第二个参数)匹配的对象。

let whatIsInAName = (arr, obj) => arr.filter(o => Object.keys(obj).every(k => obj[k] === o[k]));

console.log(whatIsInAName([{ "apple": 1, "bat": 2 }, { "bat": 2 }, { "apple": 1, "bat": 2, "cookie": 2 }], { "apple": 1, "bat": 2 }));
console.log(whatIsInAName([{ "first": "Romeo", "last": "Montague" }, { "first": "Mercutio", "last": null }, { "first": "Tybalt", "last": "Capulet" }], { "last": "Capulet" }));
console.log(whatIsInAName([{ "apple": 1, "bat": 2 }, { "apple": 1 }, { "apple": 1, "bat": 2, "cookie": 2 }], { "apple": 1, "cookie": 2 }));
console.log(whatIsInAName([{ "apple": 1, "bat": 2 }, { "apple": 1 }, { "apple": 1, "bat": 2, "cookie": 2 }, { "bat":2 }], { "apple": 1, "bat": 2 }));
.as-console-wrapper { max-height: 100% !important; top: 0; }

【讨论】:

  • 谢谢!实际上这种方法效果更好,但只是想澄清一些我可能不理解的概念,因为我仍然是这方面的初学者=)
【解决方案2】:

map 部分将source 的所有键值对映射到一个布尔数组,指示该值是否在 obj 中:

 var obj = { a: 1, c: 3 };
 var source = { a: 1, b: 2, c: 3 };

 var mapped = Object.keys(source).map(key => obj[key] === source[key]);

 console.log(mapped); // [true, false, true]

现在数组不能作为返回值直接过滤,因为数组总是真实的,不管里面有什么。现在 reducer 将该数组转换为一个布尔值,如下所示:

 [true, false, true].reduce((a, b) => a && b) // false

等同于:

 true && false && true // false

因此,如果所有键值都存在,则最后返回 true。


PS:停止这门课程,建议的代码很糟糕。

【讨论】:

  • 谢谢,它完全回答了我的疑问 =) PS:我也知道这一点,但似乎是至少了解事情如何工作的好方法,即使代码不是最佳实践,那为什么还在读哈哈 =)
  • 还有一个问题:因为我还希望映射的结果与映射的 var 相似,但结果却返回了整个字符串。我能知道这是为什么吗?
猜你喜欢
  • 2021-12-02
  • 1970-01-01
  • 1970-01-01
  • 2017-02-17
  • 2020-08-09
  • 2022-10-14
  • 1970-01-01
  • 2020-08-27
  • 1970-01-01
相关资源
最近更新 更多