比较对象数组中的所有值与一个对象

3

我有以下数据:

const myArr = [{
  id: 0,
  company: "microsoft",
  location: "berlin"
}, {
  id: 1,
  company: "google",
  location: "london"
}, {
  id: 2,
  company: "twitter",
  location: "berlin"
}];

let myObj = {
  company: ["google", "twitter"],
  location: ["london"]
}

考虑到myObj.company的条目会发生变化(无论如何),我正在尝试创建一个函数来过滤结果,并仅返回满足locationcompany条件的对象。

在上面的示例中,我们需要返回的是:

{ 
  id: 1,
  company: "google",
  location: "london"
}

如果myObj已经
let myObj = {
  company: ["google", "twitter"],
  location: []
}

那么返回的结果应该是:
{ 
  id: 1,
  company: "google",
  location: "london"
},
{ 
  id: 2,
  company: "twitter",
  location: "berlin"
}

你给出的例子的预期结果是什么? - ibrahim mahrir
你的迭代有什么问题?请在问题中添加你尝试过的代码。 - Teemu
我只是重新表达了我的问题,会进一步编辑它。 - George Katsanos
感谢所有精彩的回答,我没想到会得到这样的反馈。 - George Katsanos
3个回答

2
使用 Array#filter 方法与 Array#includes 方法(如果需要支持旧浏览器则使用 Array#indexOf 方法)。
myArr.filter(o => (myObj.company.length == 0 || myObj.company.includes(o.company)) && (myObj.location.length == 0 || myObj.location.includes(o.location)))

const myArr = [{
  id: 0,
  company: "microsoft",
  location: "berlin"
}, {
  id: 1,
  company: "google",
  location: "london"
}, {
  id: 2,
  company: "twitter",
  location: "berlin"
}];

let myObj = {
  company: ["google", "twitter"],
  location: ["london"]
}

console.log(
  myArr.filter(o => (myObj.company.length == 0 || myObj.company.includes(o.company)) && (myObj.location.length == 0 || myObj.location.includes(o.location)))
)

myObj = {
  company: ["google", "twitter"],
  location: []
}

console.log(
  myArr.filter(o => (myObj.company.length == 0 || myObj.company.includes(o.company)) && (myObj.location.length == 0 || myObj.location.includes(o.location)))
)


更新:如果有 n 个属性集合,那么你需要做一些变化,可以使用 Object.keysArray#every 方法。
var keys = Object.keys(myObj);

myArr.filter(o => keys.every(k => myObj[k].length == 0 || myObj[k].includes(o[k])))

const myArr = [{
  id: 0,
  company: "microsoft",
  location: "berlin"
}, {
  id: 1,
  company: "google",
  location: "london"
}, {
  id: 2,
  company: "twitter",
  location: "berlin"
}];

let myObj = {
  company: ["google", "twitter"],
  location: ["london"]
}

var keys = Object.keys(myObj);
console.log(
  myArr.filter(o => keys.every(k => myObj[k].length == 0 || myObj[k].includes(o[k])))
)

myObj = {
  company: ["google", "twitter"],
  location: []
}
keys = Object.keys(myObj);
console.log(
  myArr.filter(o => keys.every(k => myObj[k].length == 0 || myObj[k].includes(o[k])))
)


谢谢。我给你点赞是因为 1)我不知道 includes!2)简洁、简短、易读。评论:你在分别测试每个数组(位置、公司),所以如果我有2-3个包含其他数据的不同表格,它就不会这么DRY了。 - George Katsanos

1
使用Array.prototype.filterArray.prototype.everyObject.keys来获得所需的结果,如下所示:(请注意,obj可以具有任意数量的键,它是灵活的)

const myArr = [{
  id: 0,
  company: "microsoft",
  location: "berlin"
}, {
  id: 1,
  company: "google",
  location: "london"
}, {
  id: 2,
  company: "twitter",
  location: "berlin"
}];

let myObj = {
  company: ["google", "twitter"],
  location: ["london"]
}

function find(arr, obj) {
  // get only the keys from obj that their corresponding array is not empty
  var keys = Object.keys(obj).filter(k => obj[k].length !== 0);

  // return a filtered array of objects that ...
  return arr.filter(o => {
    // ... met the creteria (for every key k in obj, the current object o must have its value of the key k includded in the array obj[k])
    return keys.every(k => {
      return obj[k].indexOf(o[k]) != -1;   
    });
  });
}

console.log(find(myArr, myObj));


谢谢,选择为正确的原因是:1/注释 2/避免不必要的循环 3/易读 - George Katsanos

1
你可以通过迭代条件的键并检查内容是否相等以及数组长度是否不为零来进行过滤。

const filterBy = (array, criteria) => array.filter(o => 
    Object.keys(criteria).every(k =>
        criteria[k].some(c => c === o[k]) || !criteria[k].length)
);

const myArr = [{ id: 0, company: "microsoft", location: "berlin" }, { id: 1, company: "google", location: "london" }, { id: 2, company: "twitter", location: "berlin" }];

console.log(filterBy(myArr, { company: ["google", "twitter"], location: ["london"] }));
console.log(filterBy(myArr, { company: ["google", "twitter"], location: [] }));
.as-console-wrapper { max-height: 100% !important; top: 0; }

使用Array#includes代替Array#some

const filterBy = (array, criteria) => array.filter(o => 
    Object.keys(criteria).every(k => criteria[k].includes(o[k]) || !criteria[k].length)
);

const myArr = [{ id: 0, company: "microsoft", location: "berlin" }, { id: 1, company: "google", location: "london" }, { id: 2, company: "twitter", location: "berlin" }];

console.log(filterBy(myArr, { company: ["google", "twitter"], location: ["london"] }));
console.log(filterBy(myArr, { company: ["google", "twitter"], location: [] }));
.as-console-wrapper { max-height: 100% !important; top: 0; }


因为控制台包装器的黑客技巧和非常可扩展的解决方案,所以我给它加了一个+1!不过,阅读所有这些嵌套的数组函数确实需要一些时间。最终我们使用了filterkeyseverysome,所以我想知道是否有更详细但也更易读的方法来完成它。 - George Katsanos

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接