在JavaScript中使用map和reduce来过滤数组中的对象

时间:2018-09-23 14:09:10

标签: javascript filter mapping reduce

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函数将遍历所有键和值对以检查其是否匹配,并返回带有布尔值的数组,即sth,例如[{true,false},{false,false }]等,并将布尔值传递给reduce函数。

但是,当我使用以下脚本测试map函数时:

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)

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

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

  2. 在reduce函数中,该函数在map函数之后,它如何获得映射到布尔值的单个布尔值,该值指示所有srcKeys是否都通过上述条件?例如,在这种情况下,reduce函数是否简单地获取map的返回值并进一步进行计算?

非常感谢您的提前帮助!

2 个答案:

答案 0 :(得分: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; }

答案 1 :(得分:1)

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:停止这门课程,建议的代码太糟糕了。