JavaScript: 使用对象过滤对象数组

JavaScript: filter array of objects using an object

我正在尝试从 freecodecamp 进行以下挑战:https://www.freecodecamp.org/learn/javascript-algorithms-and-data-structures/intermediate-algorithm-scripting/wherefore-art-thou 我对此有几个问题。

  1. 为什么我的尝试在我的本地控制台上有效,但在 freecodecamp 上无效?意思是,在所有测试中,4 个中有 3 个在我的控制台中是正确的,但其中 none 在 FCC 上。
  2. 为什么这个测试 whatIsInAName([{ "apple": 1, "bat": 2 }, { "bat": 2 }, { "apple": 1, "bat": 2, "cookie": 2 }], { "apple": 1, "bat": 2 }) 没有通过,而其他所有测试都通过了?

我的尝试与预期结果:

function whatIsInAName(collection, source) {
  const arr = [];
  // Only change code below this line
  let finalObj = collection
    .map(item => Object.entries(item))
    .filter(el => String(el).includes(String(Object.values(source))))
    .map(el => Object.fromEntries(el))
  arr.push(finalObj);
  console.log(arr);
  // Only change code above this line
  return arr;
}
    
whatIsInAName([{ first: "Romeo", last: "Montague" }, { first: "Mercutio", last: null }, { first: "Tybalt", last: "Capulet" }], { last: "Capulet" }) // should return [{ first: "Tybalt", last: "Capulet" }]
whatIsInAName([{ "apple": 1 }, { "apple": 1 }, { "apple": 1, "bat": 2 }], { "apple": 1 }) // should return [{ "apple": 1 }, { "apple": 1 }, { "apple": 1, "bat": 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 }]
whatIsInAName([{"a": 1, "b": 2, "c": 3}], {"a": 1, "b": 9999, "c": 3}) // should return []

  • 使用Object#entries,从source
  • 获取键值对列表
  • 使用Array#filter, iterate over collection. In every iteration, using Array#every,检查上面sourceEntries中的所有条目是否匹配当前对象

function whatIsInAName(collection, source) {
  const sourceEntries = Object.entries(source);
  return collection.filter(e =>
    sourceEntries.every(([key, value]) => e[key] === value)
  );
}

console.log(
  whatIsInAName([{ first: "Romeo", last: "Montague" }, { first: "Mercutio", last: null }, { first: "Tybalt", last: "Capulet" }], { last: "Capulet" })
);
console.log(
  whatIsInAName([{ "apple": 1 }, { "apple": 1 }, { "apple": 1, "bat": 2 }], { "apple": 1 })
);
console.log(
  whatIsInAName([{ "apple": 1, "bat": 2 }, { "bat": 2 }, { "apple": 1, "bat": 2, "cookie": 2 }], { "apple": 1, "bat": 2 }) 
);
console.log(
  whatIsInAName([{ "a": 1, "b": 2, "c": 3 }], { "a": 1, "b": 9999, "c": 3 })
);

为了分析您的代码,我们先添加日志:

function whatIsInAName(collection, source) {
  const arr = [];
  let finalObj = collection
    .map(item => { 
      const entries = Object.entries(item);
      console.log(1, entries);
      return entries;
    })
    .filter(el => {
      console.log(2, String(el), String(Object.values(source)));
      return String(el).includes(String(Object.values(source)))
    })
    .map(el => {
      const obj = Object.fromEntries(el);
      console.log(3, obj);
      return obj;
    });
  console.log(4, finalObj);
  arr.push(finalObj);
  console.log(5, arr);
  return arr;
}
    
whatIsInAName([{ "apple": 1, "bat": 2 }], { "apple": 1, "bat": 2 });

总而言之,您的方法是迭代 collection,将每个项目转换为条目列表。然后,通过检查项目的条目(字符串化)是否包含源(字符串化)的值来过滤这些条目。之后,将通过过滤的条目转换回对象,从而生成对象数组。将此数组添加到初始数组和 return 后者。

问题:

  • source 有多个 属性 时它停止工作,例如,您将检查“apple,1,bat,2”是否包含“1,2”。即使您在此处检查 source 条目,您仍然会假设属性的顺序。总之,将对象字符串化不是正确的方法,这就是为什么最好检查 source 中的每个键是否与其在给定项目中的值匹配。
  • 第三个 Array#map return 是一个数组,然后您将其添加 (finalObj) 到另一个数组 arr