What is most efficient / elegant way to achieve sql-like filtering effect. I want to filter them and get only that objects which are max value in some group.
This is
Reduce the array to an object, using the name
property as the key. For each item, check if the item that exists in the accumulator has a higher value than the current item, and if not replace it with the current item. Convert back to an array with Object.values():
const arr = [{"name":"bathroom","value":54,"timeStamp":1562318089713},{"name":"bathroom","value":55,"timeStamp":1562318090807},{"name":"bedroom","value":48,"timeStamp":1562318092084},{"name":"bedroom","value":49,"timeStamp":1562318092223},{"name":"room","value":41,"timeStamp":1562318093467}]
const result = Object.values(arr.reduce((r, o) => {
r[o.name] = (r[o.name] && r[o.name].value > o.value) ? r[o.name] : o
return r
}, {}))
console.log(result)
Here is another reduce alternative :
var arr = [{"name":"bathroom","value":54,"timeStamp":1562318089713},{"name":"bathroom","value":55,"timeStamp":1562318090807},{"name":"bedroom","value":48,"timeStamp":1562318092084},{"name":"bedroom","value":49,"timeStamp":1562318092223},{"name":"room","value":41,"timeStamp":1562318093467}];
var obj = arr.reduce((r, o) => (o.value < (r[o.name] || {}).value || (r[o.name] = o), r), {});
console.log( Object.values(obj) );
Doing this in stages.
Below is an example.
const input = [{"name":"bathroom","value":54,"timeStamp":1562318089713},{"name":"bathroom","value":55,"timeStamp":1562318090807},{"name":"bedroom","value":48,"timeStamp":1562318092084},{"name":"bedroom","value":49,"timeStamp":1562318092223},{"name":"room","value":41,"timeStamp":1562318093467}];
const output = [...new Set(input.map(m => m.name))].
map(m => [...input].sort(
(a,b) => b.value - a.value).
find(x => m === x.name));
console.log(output);
What is most efficient / elegant way to achieve sql-like filtering effect.
You could take functions for every step and pipe all functions for a single result.
For example in SQL, you would have the following query:
SELECT name, value, MAX(timeStamp)
FROM data
GROUP BY name;
With an SQL like approach, you could group first and take the max object out of the result sets.
result = pipe(
groupBy('name'),
select(max('timeStamp'))
)(data);
const
pipe = (...functions) => input => functions.reduce((acc, fn) => fn(acc), input),
groupBy = key => array => array.reduce((r, o) => {
var temp = r.find(([p]) => o[key] === p[key])
if (temp) temp.push(o);
else r.push([o]);
return r;
}, []),
max = key => array => array.reduce((a, b) => a[key] > b[key] ? a : b),
select = fn => array => array.map(fn);
var data = [{ name: 'bathroom', value: 54, timeStamp: 1562318089713 }, { name: 'bathroom', value: 55, timeStamp: 1562318090807 }, { name: 'bedroom', value: 48, timeStamp: 1562318092084 }, { name: 'bedroom', value: 49, timeStamp: 1562318092223 }, { name: 'room', value: 41, timeStamp: 1562318093467 }],
result = pipe(
groupBy('name'),
select(max('timeStamp'))
)(data);
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
You can use .reduce() by keeping an accumulated object which keeps the max group currently found and then use Object.values() to get an array of those objects (instead of an key-value pair object relationship).
See example below:
const arr=[{name:"bathroom",value:54,timeStamp:1562318089713},{name:"bathroom",value:55,timeStamp:1562318090807},{name:"bedroom",value:48,timeStamp:1562318092084},{name:"bedroom",value:49,timeStamp:1562318092223},{name:"room",value:41,timeStamp:1562318093467}];
const res = Object.values(arr.reduce((acc, o) => {
acc[o.name] = acc[o.name] || o;
if (o.value > acc[o.name].value)
acc[o.name] = o;
return acc;
}, {}));
console.log(res);
Use map()
and foreach()
to get desired output
const arr=[{name:"bathroom",value:54,timeStamp:1562318089713},
{name:"bathroom",value:55,timeStamp:1562318090807},
{name:"bedroom",value:48,timeStamp:1562318092084},
{name:"bedroom",value:49,timeStamp:1562318092223},
{name:"room",value:41,timeStamp:1562318093467}];
let res = new Map();
arr.forEach((obj) => {
let values = res.get(obj.name);
if(!(values && values.value > obj.value)){
res.set(obj.name, obj)
}
})
console.log(res);
console.log([...res])