How to filter data from array of array?.
pls find the explanation in below given example.
We must use startnumber and endnumber in data query.
const data = [
{
"name": "x",
"points": [
[100, 50, 1], //[number, value, bit]
[150, 51, 0],
[170, 52, 1],
[200, 53, 0]
]
},
{
"name": "y",
"points": [
[60, 50, 1],
[100, 5, 1],
[150, 6, 0],
[170, 7, 1],
[200, 53, 1]
]
},
{
"name": "z",
"points": [
[300, 50, 1],
[350, 51, 0],
[370, 52, 1],
[400, 53, 1]
]
}
]
// want to find the records with name equal to x & y and number between 100 to 170
const names = ["x", "y"];
const startnumber = 100;
const endnumber = 170;
const finalResult= [];
for(const n of names){
console.log('name', n);
console.log('startnumber', startnumber)
console.log('endnuumber', endnumber)
const result = data.find(x=>x.name === n)
// how to use startnumber and endnumber here in above line/query ? OR some other elegant solution is required
if(result){
finalResult.push('result', result);
}
}
if(finalResult.length){
console.log(finalResult);
}
[
{
"name": "x",
"points": [
[100, 50, 1],
[150, 51, 0],
[170, 52, 1],
]
},
{
"name": "y",
"points": [
[100, 5, 1],
[150, 6, 0],
[170, 7, 1],
]
}
]
const results = data.filter(elem => !!names.find(name => name == elem.name))
Explanation:
data.filter applies the callback to each element of the array datanames.find applies the callback to each element of the array names in order to find a match.!! is used because find returns an element, so !! causes a double negation that turns it into a boolean, the expected return from the find callback (its actually not strictly necessary, as find returning undefined would be coerced to false), but it clarifies the intention.data that have names properties that match the values in names.const data = [
{
"name": "x",
"points": [
[100, 50, 1], //[number, value, bit]
[150, 51, 0],
[170, 52, 1],
[200, 53, 0]
]
},
{
"name": "y",
"points": [
[60, 50, 1],
[100, 5, 1],
[150, 6, 0],
[170, 7, 1],
[200, 53, 1]
]
},
{
"name": "y",
"points": [
[60, 50, 1],
[200, 53, 1]
]
},
{
"name": "z",
"points": [
[300, 50, 1],
[350, 51, 0],
[370, 52, 1],
[400, 53, 1]
]
}
]
// want to find the records with name equal to x & y and number between 100 to 170
const names = ["x", "y"];
const startNumber = 100;
const endNumber = 170;
const results = data
.filter(elem => !!names.find(name => name == elem.name))
.map(elem => {
return {
name: elem.name,
points: elem.points.filter(point => point[0] >= startNumber && point[0] <= endNumber)
}
})
.filter(elem => elem.points.length > 0)
console.log(results)
The task and the two given data structures imply a two folded filter process for each data item.
names array).points array by whether a points item's first array item (the number value) is within a certain number range (which is defined by the additionally provided startnumber and endnumber values).Thus a viable approach was to reduce the provided data array by a reducer function which for each data item takes care of the above two tasks.
The reducer function's initial value will be kind of a config and/or collector object which features ...
name lookup (applied as a Map instance) for the to be explicitly processed data items.startnumber and endnumber range values as lowerNumber respectively upperNumber.result array where only those data items get pushed into which fulfill all requirements.function collectItemsByNameWhichHavePointsInNumberRange(collector, item) {
const { nameLookup, lowerNumber, upperNumber, result } = collector;
let { name, points } = item;
// ... collect items by name ...
if (nameLookup.has(name)) {
points = points
.filter(([number]) =>
(number >= lowerNumber) && (number <= upperNumber)
);
// ... which (actually do) have points (with)in (a) number range.
// (according to the above `points` filter result)
if (points.length >= 1) {
result
.push({
...item,
points,
});
}
}
return collector;
}
const data = [{
name: "x",
points: [
//[number, value, bit]
[100, 50, 1],
[150, 51, 0],
[170, 52, 1],
[200, 53, 0],
],
}, {
name: "y",
points: [
[60, 50, 1],
[100, 5, 1],
[150, 6, 0],
[170, 7, 1],
[200, 53, 1],
],
}, {
name: "z",
points: [
[300, 50, 1],
[350, 51, 0],
[370, 52, 1],
[400, 53, 1],
],
}];
const names = ["x", "y"];
const startnumber = 100;
const endnumber = 170;
const { result } = data
.reduce(collectItemsByNameWhichHavePointsInNumberRange, {
nameLookup: new Map(names.map(value => [value, value])),
lowerNumber: startnumber,
upperNumber: endnumber,
result: [],
});
console.log({ result });
.as-console-wrapper { min-height: 100%!important; top: 0; }
The most elegant solution:
const res = data.reduce((acc, curr) => {
const { name, points } = curr
const filteredPoints = points.filter(p => p[0] >= startNumber && p[0] <= endNumber)
return names.includes(name) && filteredPoints.length > 0 ? acc.concat({ name, points: filteredPoints }) : acc
}, [])