如果我有以下数组:
var myArray = [
{sa67g:{id:'sa67g', name: 'Leo', value: 50}},
{sa86w:{id:'sa86w', name: 'Amy', value: 40}},
{sa33p:{id:'sa33p', name: 'Alex', value: 30}},
{sa74x:{id:'sa74x', name: 'John', value: 20}},
{sa67g:{id:'sa67g', name: 'Leo', value: 10}},
{sa33p:{id:'sa33p', name: 'Alex', value: 15}},
]
使用lodash获取具有无重复项目的单个数组的最佳方法是什么,其值之和按降序排序,用于另一个数组中所有重复项目?
预期结果应该是这样的:
result = [{sa67g:{id:'sa67g', name: 'Leo', value: 60}},
{sa33p:{id:'sa33p', name: 'Alex', value: 45}},
{sa86w:{id:'sa86w', name: 'Amy', value: 40}},
{sa74x:{id:'sa74x', name: 'John', value: 20}}
]
我相信有很多方法可以做到这一点。在我的头顶上,我会使用 reduce
将您的对象数组转换为一个具有求和值的对象。使用 chain
与其他一些 lodash 方法结合使用进行排序和转换,它看起来像这样:
const result = _.chain(myArray)
.map(person => _.values(person))
.flatten()
.reduce((summed, person) => {
if (!summed[person.id]) {
summed[person.id] = person
} else {
summed[person.id].value += person.value
}
return summed
}, {})
.values()
.orderBy(['value'], ['desc'])
.map(person => ({ [person.id]: person }))
.value()
lodash 的_.mergeWith()
将所有对象合并为一个对象。由于_.mergeWith
是递归的,内部属性也将合并,我们可以使用它来对value
属性求和。之后,我们使用_.map()
将对象转换回数组:
const myArray = [{"sa67g":{"id":"sa67g","name":"Leo","value":50}},{"sa86w":{"id":"sa86w","name":"Amy","value":40}},{"sa33p":{"id":"sa33p","name":"Alex","value":30}},{"sa74x":{"id":"sa74x","name":"John","value":20}},{"sa67g":{"id":"sa67g","name":"Leo","value":10}},{"sa33p":{"id":"sa33p","name":"Alex","value":15}}];
const result = _.map(
// merge all objects into a single object, and sum the value property
_.mergeWith({}, ...myArray, (objValue = 0, srcValue = 0, key) => key === 'value' ? objValue + srcValue : undefined),
// split back into an array of objects
(v, k) => ({ [k]: v })
)
console.log(result);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.4/lodash.min.js"></script>
-
过滤掉单个值的最简单方法是使用
Set
。使用它来获取一组唯一键。 -
通过迭代键并计算总和来创建所需的对象。
使用本机方法并假设支持 es8:
var myArray = [
{sa67g:{id:'sa67g', name: 'Leo', value: 50}},
{sa86w:{id:'sa86w', name: 'Amy', value: 40}},
{sa33p:{id:'sa33p', name: 'Alex', value: 30}},
{sa74x:{id:'sa74x', name: 'John', value: 20}},
{sa67g:{id:'sa67g', name: 'Leo', value: 10}},
{sa33p:{id:'sa33p', name: 'Alex', value: 15}},
]
var tmp = myArray.map(o => Object.values(o)[0])
.reduce((a, c) => {
const obj = a[c.name]
if (obj) {
obj.id = c.id > obj.id ? c.id : obj.id;// set highest id
obj.value += c.value; //increment vlues
} else {
a[c.name] = Object.assign({},c);
}
return a;
}, {});
var res = Object.values(tmp)
.sort((a, b) => b.value - a.value)
.map(o => ({[o.id]:o }))
console.log(res)
.as-console-wrapper { max-height: 100%!important;}
您可以采取循序渐进的方法,并使用管道为下一个函数获取 reutl。
var array = [{ sa67g: { id: 'sa67g', name: 'Leo', value: 50 } }, { sa86w: { id: 'sa86w', name: 'Amy', value: 40 } }, { sa33p: { id: 'sa33p', name: 'Alex', value: 30 } }, { sa74x: { id: 'sa74x', name: 'John', value: 20 } }, { sa67g: { id: 'sa67g', name: 'Leo', value: 10 } }, { sa33p: { id: 'sa33p', name: 'Alex', value: 15 } }],
pipe = (...fn) => arg => fn.reduce((x, f) => f(x), arg),
objects = array => array.map(o => Object.assign({}, Object.values(o)[0])),
sum = array => array.reduce((m, o) => {
if (m.has(o.id)) {
m.get(o.id).value += o.value;
} else {
m.set(o.id, o);
}
return m;
}, new Map),
values = map => Array.from(map.values()),
sort = array => array.sort((a, b) => b.value - a.value),
map = array => array.map(o => ({ [o.id]: o })),
path = pipe(objects, sum, values, sort, map),
result = path(array);
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
对象属性永远不应该是值(即键或 id(——要创建键值关联,请改用 Map。
const concat = ({ id: id1, name: name1, value: v1 }, { id: id2, name: name2, value: v2 }) =>
({ id: id1, name: name1, value: v1 + v2 })
const main = xs =>
xs.map (x => Object.entries (x) [ 0 ])
.reduce ((acc, [ key, value ]) =>
acc.has (key)
? acc.set (key, concat (value, acc.get (key)))
: acc.set (key, value), new Map)
const myArray =
[ {sa67g:{id:'sa67g', name: 'Leo', value: 50}}
, {sa86w:{id:'sa86w', name: 'Amy', value: 40}}
, {sa33p:{id:'sa33p', name: 'Alex', value: 30}}
, {sa74x:{id:'sa74x', name: 'John', value: 20}}
, {sa67g:{id:'sa67g', name: 'Leo', value: 10}}
, {sa33p:{id:'sa33p', name: 'Alex', value: 15}}
]
console.log (main (myArray))
// => Map {
// 'sa67g' => { id: 'sa67g', name: 'Leo', value: 60 },
// 'sa86w' => { id: 'sa86w', name: 'Amy', value: 40 },
// 'sa33p' => { id: 'sa33p', name: 'Alex', value: 45 },
// 'sa74x' => { id: 'sa74x', name: 'John', value: 20 } }
如果要将 Map 转换回对象,可以使用此
const mapToObject = m =>
Array.from(m.entries ()).reduce ((acc, [ k, v ]) =>
Object.assign (acc, { [ k ]: v }), {})