基于另一个数组(非静态)的键的对象数组子集,然后过滤
Subset array of object based on keys from another array(not static) and then filter
我有一个对象数组,需要根据特定值进行过滤:
let data =
[
{
"region": 28,
"nuts": 33,
"score" : 26
},
{
"region": 18,
"nuts": 22,
"score" : 21
}
]
另一个数组包含上述对象要被过滤和子集化的键:
// this changes everytime
// it may include ALL the keys or only ONE key of above object
let keysArray = ["region", "score"]
(OR )
let keysArray = ["region", "nuts"]
现在,如果 data
需要针对 25 以上的 region
和 score
进行过滤,那么它应该 return 以下内容:
// when => keysArray = ["region", "score"]
// region && score >= 25
// expected output
[
{
"region": 28,
"score" : 26
}
]
// when => keysArray = ["region", "nuts"]
// region && nuts >= 25
// expected output
[
{
"region": 28,
"nuts" : 33
}
]
如何实现?
提前致谢。
PS :这没有回答问题 -
filtering an array of objects based on another array in javascript
我创建了一个工作片段。
let data = [{
region: 28,
nuts: 33,
score: 26
},
{
region: 18,
nuts: 22,
score: 21
}
];
// this changes everytime
// it may include ALL the keys or only ONE key of above object
let keysArray = ["region", "score"];
// Write Javascript code!
const appDiv = document.getElementById("app");
appDiv.innerHTML = `<h1>JS Starter</h1>`;
const resultDiv = document.getElementById("result");
filterData(keysArray, 25).forEach(item => {
resultDiv.innerHTML += `<li>region: ${item.region}, score: ${
item.score
}</li>`;
});
function filterData(keys, val) {
let result = [];
data.forEach(dataItem => {
let isEligible = false;
for (let i = 0; i < keys.length; i++) {
let key = keys[i];
isEligible = dataItem[key] >= val;
if (!isEligible) break;
}
if (isEligible) result.push(dataItem);
});
return result;
}
<div id="app"></div>
<ul id="result"></ul>
stackblitz 中的工作演示:
https://stackblitz.com/edit/js-swutjy?embed=1&file=index.js
let data =
[
{
"region": 28,
"nuts": 33,
"score" : 26
},
{
"region": 18,
"nuts": 22,
"score" : 21
}
];
let keysArray = ["region", "nuts"];
const hasValAboveThreshold = (item, threshold) => {
return keysArray.every((key) => item[key] > threshold);
}
const getItem = (item) => {
return keysArray.reduce((acc, key) => {
acc[key] = item[key];
return acc;
}, {});
}
const output = data.reduce((acc, val) => {
if (hasValAboveThreshold(val, 25)) {
acc.push(getItem(val));
}
return acc;
}, []);
console.log(output);
使用 Underscore(或 Lodash),您可以编写更短的代码。
// The function that will do the trick.
function subsetFilter(data, keys, predicate) {
return _.chain(data)
.map(_.partial(_.pick, _, keys))
.filter(_.partial(_.every, _, predicate))
.value();
}
// Usage.
subsetFilter(data, ['region', 'nuts'], x => x >= 25);
让我们把它分解成碎片。
function subsetFilter(data, keys, predicate) {
我们创建一个具有三个参数的函数:要进行子集化和过滤的数据、可能可变的键数组以及 predicate
,它可以是 return 的任何函数布尔值。比如我上面用x => x >= 25
表示属性应该大于等于25.
_.chain(data)
我们将数据包装在一个特殊的包装器对象中,这将允许我们链接多个 Underscore 函数,每个函数处理链中前一个函数的结果 (doc)。
_.pick
这是一个接受两个参数的函数:一个对象和一个键数组。它 return 是对象的副本,仅包含名称列在键数组 (doc) 中的属性。例如:
_.pick({a: 1, b: 2}, ['a', 'c']) // returns {a: 1}
接下来,
_.partial(_.pick, _, keys)
这会将 _.pick
转换为一个新函数,其中第二个参数已经预先填充了 keys
。 _
表示 _.pick
的修改版本仍在寻找它的第一个参数 (doc)。它等效于以下函数:
function(obj) {
return _.pick(obj, keys);
}
完成这一行,
.map(_.partial(_.pick, _, keys))
我们在链式 data
包装器上调用 _.map
,生成一个新数组,其中每个元素都通过我们使用 _.partial
和 _.pick
创建的函数进行了转换.在我们的示例中,此时链包装器包含以下数据:
[
{
"region": 28,
"nuts": 33
},
{
"region": 18,
"nuts": 22
}
]
(所以基本上仍然是相同的数据,只是 score
属性不再存在,因为我们没有 _.pick
它们。)
_.partial(_.every, _, predicate)
同样,我们使用 _.partial
创建函数的修改版本,其中第二个参数已经预先填充。这一次,基函数是 _.every
,它接受一个数组或对象和一个谓词。它returns true
如果谓词returns true
用于数组的每个元素或对象的每个属性,否则false
。预填充的第二个参数是 subsetFilter
函数的 predicate
参数。基本上我们在这里声明以下内容:给这个函数一个对象,它会告诉你它的所有属性是否满足 predicate
.
.filter(_.partial(_.every, _, predicate))
我们 _.filter
我们链中的中间结果与我们刚刚使用 _.partial
和 _.every
创建的函数。我们只保留数组中每个 属性 满足 predicate
的对象。此时,我们的链包装器包含以下值:
[
{
"region": 28,
"nuts": 33
}
]
这是你想要的结果,但它仍然是包裹的。因此,作为最后一步,我们删除包装器 (doc):
.value();
这是我们表达式的结尾,也是我们从函数 return 得到的结果。
我有一个对象数组,需要根据特定值进行过滤:
let data =
[
{
"region": 28,
"nuts": 33,
"score" : 26
},
{
"region": 18,
"nuts": 22,
"score" : 21
}
]
另一个数组包含上述对象要被过滤和子集化的键:
// this changes everytime
// it may include ALL the keys or only ONE key of above object
let keysArray = ["region", "score"]
(OR )
let keysArray = ["region", "nuts"]
现在,如果 data
需要针对 25 以上的 region
和 score
进行过滤,那么它应该 return 以下内容:
// when => keysArray = ["region", "score"]
// region && score >= 25
// expected output
[
{
"region": 28,
"score" : 26
}
]
// when => keysArray = ["region", "nuts"]
// region && nuts >= 25
// expected output
[
{
"region": 28,
"nuts" : 33
}
]
如何实现? 提前致谢。
PS :这没有回答问题 - filtering an array of objects based on another array in javascript
我创建了一个工作片段。
let data = [{
region: 28,
nuts: 33,
score: 26
},
{
region: 18,
nuts: 22,
score: 21
}
];
// this changes everytime
// it may include ALL the keys or only ONE key of above object
let keysArray = ["region", "score"];
// Write Javascript code!
const appDiv = document.getElementById("app");
appDiv.innerHTML = `<h1>JS Starter</h1>`;
const resultDiv = document.getElementById("result");
filterData(keysArray, 25).forEach(item => {
resultDiv.innerHTML += `<li>region: ${item.region}, score: ${
item.score
}</li>`;
});
function filterData(keys, val) {
let result = [];
data.forEach(dataItem => {
let isEligible = false;
for (let i = 0; i < keys.length; i++) {
let key = keys[i];
isEligible = dataItem[key] >= val;
if (!isEligible) break;
}
if (isEligible) result.push(dataItem);
});
return result;
}
<div id="app"></div>
<ul id="result"></ul>
stackblitz 中的工作演示: https://stackblitz.com/edit/js-swutjy?embed=1&file=index.js
let data =
[
{
"region": 28,
"nuts": 33,
"score" : 26
},
{
"region": 18,
"nuts": 22,
"score" : 21
}
];
let keysArray = ["region", "nuts"];
const hasValAboveThreshold = (item, threshold) => {
return keysArray.every((key) => item[key] > threshold);
}
const getItem = (item) => {
return keysArray.reduce((acc, key) => {
acc[key] = item[key];
return acc;
}, {});
}
const output = data.reduce((acc, val) => {
if (hasValAboveThreshold(val, 25)) {
acc.push(getItem(val));
}
return acc;
}, []);
console.log(output);
使用 Underscore(或 Lodash),您可以编写更短的代码。
// The function that will do the trick.
function subsetFilter(data, keys, predicate) {
return _.chain(data)
.map(_.partial(_.pick, _, keys))
.filter(_.partial(_.every, _, predicate))
.value();
}
// Usage.
subsetFilter(data, ['region', 'nuts'], x => x >= 25);
让我们把它分解成碎片。
function subsetFilter(data, keys, predicate) {
我们创建一个具有三个参数的函数:要进行子集化和过滤的数据、可能可变的键数组以及 predicate
,它可以是 return 的任何函数布尔值。比如我上面用x => x >= 25
表示属性应该大于等于25.
_.chain(data)
我们将数据包装在一个特殊的包装器对象中,这将允许我们链接多个 Underscore 函数,每个函数处理链中前一个函数的结果 (doc)。
_.pick
这是一个接受两个参数的函数:一个对象和一个键数组。它 return 是对象的副本,仅包含名称列在键数组 (doc) 中的属性。例如:
_.pick({a: 1, b: 2}, ['a', 'c']) // returns {a: 1}
接下来,
_.partial(_.pick, _, keys)
这会将 _.pick
转换为一个新函数,其中第二个参数已经预先填充了 keys
。 _
表示 _.pick
的修改版本仍在寻找它的第一个参数 (doc)。它等效于以下函数:
function(obj) {
return _.pick(obj, keys);
}
完成这一行,
.map(_.partial(_.pick, _, keys))
我们在链式 data
包装器上调用 _.map
,生成一个新数组,其中每个元素都通过我们使用 _.partial
和 _.pick
创建的函数进行了转换.在我们的示例中,此时链包装器包含以下数据:
[
{
"region": 28,
"nuts": 33
},
{
"region": 18,
"nuts": 22
}
]
(所以基本上仍然是相同的数据,只是 score
属性不再存在,因为我们没有 _.pick
它们。)
_.partial(_.every, _, predicate)
同样,我们使用 _.partial
创建函数的修改版本,其中第二个参数已经预先填充。这一次,基函数是 _.every
,它接受一个数组或对象和一个谓词。它returns true
如果谓词returns true
用于数组的每个元素或对象的每个属性,否则false
。预填充的第二个参数是 subsetFilter
函数的 predicate
参数。基本上我们在这里声明以下内容:给这个函数一个对象,它会告诉你它的所有属性是否满足 predicate
.
.filter(_.partial(_.every, _, predicate))
我们 _.filter
我们链中的中间结果与我们刚刚使用 _.partial
和 _.every
创建的函数。我们只保留数组中每个 属性 满足 predicate
的对象。此时,我们的链包装器包含以下值:
[
{
"region": 28,
"nuts": 33
}
]
这是你想要的结果,但它仍然是包裹的。因此,作为最后一步,我们删除包装器 (doc):
.value();
这是我们表达式的结尾,也是我们从函数 return 得到的结果。