如何获取具有无重复项的单个数组及其值的总和.命令描述



如果我有以下数组:

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>

  1. 过滤掉单个值的最简单方法是使用 Set 。使用它来获取一组唯一键。

  2. 通过迭代键并计算总和来创建所需的对象。

使用本机方法并假设支持 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 }), {})

最新更新