什么是实现类似sql的过滤效果的最有效/最优雅的方法。我想过滤它们,并只获取某个组中最大值的对象。
这是我的代码,它可以工作,但可能不是最好的方法:
uniqueValues = (arr) => [...new Set(arr)];
getMaxTimeOf = (arr) => Math.max(...arr.map(o => o.timeStamp), 0);
selectorName = (name) => (obj) => obj.name === name;
selectorTime = (time) => (obj) => obj.timeStamp === time;
getGroup = (obj, selector) => obj.filter(selector)
onlyLastChangedFrom = (history) => {
const uniqueNames = uniqueValues(history.map(o => o.name))
let filtered = []
uniqueNames.forEach(name => {
const group = getGroup(history, selectorName(name))
const groupLastTime = getMaxTimeOf(group)
const lastChange = getGroup(group, selectorTime(groupLastTime))
filtered.push(lastChange[0])
});
return filtered
}
onlyLastChangedFrom(history)
// 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 } ]
// Output:
[ { name: 'bathroom',
value: 55,
timeStamp: 1562318090807 },
{ name: 'bedroom',
value: 49,
timeStamp: 1562318092223 },
{ name: 'room',
value: 41,
timeStamp: 1562318093467 } ]
答案 0 :(得分:3)
name
属性作为键,将数组 Reduce复制到对象。对于每个项目,检查累加器中存在的项目是否具有比当前项目更高的值,如果没有,请用当前项目替换它。用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)
答案 1 :(得分:2)
什么是实现类似sql的过滤效果的最有效/最优雅的方法。
您可以为每个步骤使用功能,并通过管道传递所有功能以获得单个结果。
例如在SQL中,您将具有以下查询:
SELECT name, value, MAX(timeStamp)
FROM data
GROUP BY name;
使用类似SQL的方法,您可以先进行分组,然后将max对象从结果集中删除。
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; }
答案 2 :(得分:1)
我喜欢将lodash用于此类内容。它非常实用,因此非常清晰明了。
看看下面的代码:
const 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
}
];
let max = _
.chain(DATA)
.groupBy('name')
.sortBy('value')
.map(o => _(o).reverse().first())
.flatten()
.value();
console.log(max); // returns [{"name":"bathroom","value":55,"timeStamp":1562318090807},{"name":"bedroom","value":49,"timeStamp":1562318092223},{"name":"room","value":41,"timeStamp":1562318093467}]
答案 3 :(得分:1)
这是另一个减少方法:
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) );
答案 4 :(得分:0)
您可以使用.reduce()
,方法是保留一个累积的对象,该对象保持当前找到的最大组,然后使用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 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);
答案 5 :(得分:0)
分阶段进行。
下面是一个例子。
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);
答案 6 :(得分:0)
使用map()
和foreach()
获得所需的输出
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])