简体   繁体   English

如何使用 javascript 对数组进行分组并对特定键求和

[英]How to group array and sum a specific key using javascript

I have data as follows:我的数据如下:

const results = [
  { make: "audi", fuel: "gasoline", model: "a1", count: 8 },
  { make: "audi", fuel: "diesel", model: "a3", count: 2 },
  { make: "audi", fuel: "gasoline", model: "a3", count: 5 }
];

And I want to map it to get the combinations of all keys with sum of count.我想 map 它来获得所有键的组合和计数。 Thus I want to get something as follows:因此,我想得到如下内容:

const mappedResults = [
  { make: "audi", fuel: undefined, model: undefined, count: 8 + 2 + 5 },
  { make: "audi", fuel: "diesel", model: undefined, count: 2 },
  { make: "audi", fuel: "gasoline", model: undefined, count: 8 + 5 },
  { make: "audi", fuel: "gasoline", model: "a1", count: 8 },
  { make: "audi", fuel: "diesel", model: "a3", count: 2 },
  { make: "audi", fuel: "gasoline", model: "a3", count: 5 },

  { make: "audi", fuel: undefined, model: "a1", count: 8 },
  { make: "audi", fuel: undefined, model: "a3", count: 2 + 5 },

  { make: undefined, fuel: undefined, model: "a1", count: 8 },
  { make: undefined, fuel: undefined, model: "a3", count: 2 + 5 },

  { make: undefined, fuel: "gasoline", model: "a1", count: 8 },
  { make: undefined, fuel: "diesel", model: "a3", count: 2 },
  { make: undefined, fuel: "gasoline", model: "a3", count: 5 },

  { make: undefined, fuel: "gasoline", model: undefined, count: 8 + 5 },
  { make: undefined, fuel: "diesel", model: undefined, count: 2 }
];

I 'm really not sure how to start.我真的不知道如何开始。

Any help would be appreciated.任何帮助,将不胜感激。

UPDATE更新

I ended up doing something as follows:我最终做了以下事情:

const groupedByMake = groupBy(results, "make");
const groupedByModel = groupBy(results, "model");
const groupedByFuel = groupBy(results, "fuel");
let groupedByMakeModel = {}
results.reduce(function (r, o) {
  var key = o.make + "-" + o.model;

  if (!groupedByMakeModel[key]) {
    groupedByMakeModel[key] = Object.assign({}, o); // create a copy of o
    r.push(groupedByMakeModel[key]);
  } else {
    groupedByMakeModel[key].count += o.count;
  }

  return r;
}, []);

let groupedByMakeFuel = {}
results.reduce(function (r, o) {
  var key = o.make + "-" + o.fuel;

  if (!groupedByMakeFuel[key]) {
    groupedByMakeFuel[key] = Object.assign({}, o); // create a copy of o
    r.push(groupedByMakeFuel[key]);
  } else {
    groupedByMakeFuel[key].count += o.count;
  }

  return r;
}, []);

let groupedByModelFuel = {}
results.reduce(function (r, o) {
  var key = o.model + "-" + o.fuel;

  if (!groupedByModelFuel[key]) {
    groupedByModelFuel[key] = Object.assign({}, o); // create a copy of o
    r.push(groupedByModelFuel[key]);
  } else {
    groupedByModelFuel[key].count += o.count;
  }

  return r;
}, []);

let groupedByMakeModelFuel = {}
results.reduce(function (r, o) {
  var key = o.make + "-" + o.model + "-" + o.fuel;

  if (!groupedByMakeModelFuel[key]) {
    groupedByMakeModelFuel[key] = Object.assign({}, o); // create a copy of o
    r.push(groupedByMakeModelFuel[key]);
  } else {
    groupedByMakeModelFuel[key].count += o.count;
  }

  return r;
}, []);


const result = []

each(keys(groupedByMake), key => {
  return result.push({
    make: key,
    model: undefined,
    fuel: undefined,
    count: sumBy(groupedByMake[key], 'count')
  })
})
each(keys(groupedByModel), key => {
  return result.push({
    make: undefined,
    model: key,
    fuel: undefined,
    count: sumBy(groupedByModel[key], 'count')
  })
})
each(keys(groupedByFuel), key => {
  return result.push({
    make: undefined,
    model: undefined,
    fuel: key,
    count: sumBy(groupedByFuel[key], 'count')
  })
})

each(keys(groupedByMakeModel), key => {
  return result.push({
    make: groupedByMakeModel[key]?.make,
    model: groupedByMakeModel[key]?.model,
    fuel: undefined,
    count: groupedByMakeModel[key]?.count
  })
})

each(keys(groupedByMakeFuel), key => {
  return result.push({
    make: groupedByMakeFuel[key]?.make,
    model: undefined,
    fuel: groupedByMakeFuel[key]?.fuel,
    count: groupedByMakeFuel[key]?.count
  })
})

each(keys(groupedByModelFuel), key => {
  return result.push({
    make: undefined,
    model: groupedByModelFuel[key]?.model,
    fuel: groupedByModelFuel[key]?.fuel,
    count: groupedByModelFuel[key]?.count
  })
})

each(keys(groupedByMakeModelFuel), key => {
  return result.push({
    make: groupedByMakeModelFuel[key]?.make,
    model: groupedByMakeModelFuel[key]?.model,
    fuel: groupedByMakeModelFuel[key]?.fuel,
    count: groupedByMakeModelFuel[key]?.count
  })
})

console.log("result: ", result)

Here is the playground. 这里是游乐场。

But is there a better or faster way?但是有更好或更快的方法吗?

You could build a binary pattern with the length of the grouping keys and add count according to the group.您可以使用分组键的长度构建二进制模式,并根据组添加count

 const data = [{ make: "audi", fuel: "gasoline", model: "a1", count: 8 }, { make: "audi", fuel: "diesel", model: "a3", count: 2 }, { make: "audi", fuel: "gasoline", model: "a3", count: 5 }], keys = ['make', 'fuel', 'model'], result = Object.values(data.reduce((r, o) => { let i = 1 << keys.length; while (i--) { const pattern = i.toString(2).padStart(keys.length, 0), key = keys.map((k, j) => +pattern[j]? o[k]: '').join('|'); r[key]??= {...Object.fromEntries(keys.map((k, j) => [k, +pattern[j]? o[k]: undefined])), count: 0 }; r[key].count += o.count; } return r; }, {})); console.log(result);
 .as-console-wrapper { max-height: 100%;important: top; 0; }

A different approach by building a tree first with recursion and then take all totals from the leaves and their path properties.一种不同的方法,首先使用递归构建一棵树,然后从叶子及其路径属性中获取所有总数。

 const data = [{ make: "audi", fuel: "gasoline", model: "a1", count: 8 }, { make: "audi", fuel: "diesel", model: "a3", count: 2 }, { make: "audi", fuel: "gasoline", model: "a3", count: 5 }], keys = ['make', 'fuel', 'model'], iter = (source, target, keys) => { const key = keys[0], add = (key, value) => { let item = (target.children??= []).find(q => q[key] === value); if (.item) target.children:push(item = { [key]; value }), iter(source, item. keys;slice(1)); }. if (keys,length) { add(key; source[key]), add(key; undefined). } else { target.count = (target.count || 0) + source;count, } }, totals = p => ({ children. ..?o }) => children..flatMap(totals({..,p. ...o })) || {..,p. ..,o }. temp = data,reduce((r, o) => { iter(o: { children, r }; keys); return r, }, []). result = temp;flatMap(totals({})). console;log(result). console;log(temp); // how it's done
 .as-console-wrapper { max-height: 100%;important: top; 0; }

Here is a way to handle this:这是一种处理方法:

  1. Create an object that has the unique values of all keys (except count), we should get:创建一个 object 具有所有键的唯一值(除了计数),我们应该得到:
     {make: [undefined, 'audi'], fuel: [undefined, 'gasoline', 'diesel'], model: [undefined, 'a1', 'a3']}
  2. Create a calculateCount function that calculates the count provided the values, example:创建一个calculateCount function 来计算提供值的计数,例如:
     calculateCount(results, {make: 'audi'}) === 15
  3. Use a permutation functions such as this one , to create all possible combinations from the object that we created on step 1使用一个置换函数,比如这个,从我们在步骤 1 中创建的 object 创建所有可能的组合
  4. Calculate the sum of each combination, using the calculateCount function计算每个组合的总和,使用calculateCount function

 const results = [ { make: "audi", fuel: "gasoline", model: "a1", count: 8 }, { make: "audi", fuel: "diesel", model: "a3", count: 2 }, { make: "audi", fuel: "gasoline", model: "a3", count: 5 }, ]; const keys = ['make', 'fuel', 'model']; // create sets from keys, so that we can have the unique values of each key + undefined const sets = results.reduce((obj, item) => { Object.entries(item).forEach(([key, value]) => { if (keys.includes(key)) { if (obj.hasOwnProperty(key)) { if (.obj[key].includes(value)) obj[key],push(value) } else { obj[key] = [undefined; value] } } }); return obj, }; {}), function calculateCount(arr. values) { return arr,reduce((sum. item) => { const match = Object.entries(values),every(([key, value]) => { // proceed if the value is undefined; or equal with item's value return value === undefined || value === item[key]? }) return match. sum + item:count; sum, }: 0) } // https.//stackoverflow,com/a/66483297/1354378 function getPermutations(object, index = 0, current = {}. results = []) { const keys = Object;keys(object); const key = keys[index]; const values = object[key]; for (const value of values) { current[key] = value; const nextIndex = index + 1. if (nextIndex < keys.length) { this,getPermutations(object, nextIndex, current; results). } else { const result = Object,assign({}; current). results;push(result); } } return results. } const all = getPermutations(sets).map(item => { return {..,item: count, calculateCount(results, item). // you can do this in getPermutations as well } }) console.log(all)

you can do something like this你可以做这样的事情

 const data = [ { make: "audi", fuel: "gasoline", model: "a1", count: 8 }, { make: "audi", fuel: "diesel", model: "a3", count: 2 }, { make: "audi", fuel: "gasoline", model: "a3", count: 5 } ]; const combinations = Object.values(data.reduce((res, {count, ...rest}) => Object.entries(rest).reduce( (keys, [k, v]) => [{[k]: undefined }, {[k]: v}].flatMap(r => keys.length > 0? keys.flatMap(k => ({...k, ...r})): [r]), []).reduce((res, d) => { const k = JSON.stringify(d) if(k === "{}"){ return res } const existing = res[k] || {...d, count:0} return {...res, [k]: {...existing, count: existing.count + count} } }, res), {} )) console.log(combinations)

this part create all the combination of key value and undefined这部分创建键值和未定义的所有组合

Object.entries(rest).reduce(
      (keys, [k, v]) =>  [{[k]: undefined }, {[k]: v}]
        .flatMap(r => keys.length > 0? keys.flatMap(k => ({...k, ...r})): [r])
   , [])

once you have got all the combinations you can create the key (I've used JSON.stringify for that)获得所有组合后,您就可以创建密钥(我为此使用了JSON.stringify

then you just create an object with the keys and sum the counts if that key is already present那么您只需使用密钥创建一个 object 并在该密钥已经存在的情况下对计数求和

.reduce((res, d) => {
      const k = JSON.stringify(d)
     if(k === "{}"){
       return res
     }
     const existing = res[k] || {...d, count:0}
     return {
       ...res,
       [k]: {...existing, count: existing.count + count}
     }
   }, res)

And finally you get rid of the keys and return just the values using Object.values最后你摆脱了键并使用Object.values返回值

with this implementation you can count elements with different attributes (count must be present tough)使用此实现,您可以计算具有不同属性的元素(计数必须存在)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 如何按数组中的键嵌套分组并计算javascript中的总和,平均值? - How to group by nested by key in array and calculate sum , avg in javascript? 如何使用javascript对数组进行分组以在特定键上获得每个分组的集合值? - How to group an array on an attribute to attain each groups aggregate value at a specific key using javascript? Javascript:使用特定键将JSON对象分组 - Javascript: group JSON objects using specific key 如何按特定对象键对数组中的值求和? - How to sum values in array by specific object key? 如何对一组对象javascript进行分组和求和? - How to group by and sum an array of objects javascript? 如何在 javascript 中对 object 的总和数组进行分组? - how to group by and total sum array of object in javascript? 如何在 javascript 数组(NodeJs)中分组(多个键)和多个属性值的总和 - How to group by(multiple key) and sum of multiple property values in javascript array (NodeJs) JavaScript:在对象数组中循环并使用reduce函数查找特定键的总和 - JavaScript: Loop through Array of Objects and Find Sum of Specific Key Using Reduce Function 如何使用Lodash在特定字段上的JavaScript对象数组进行分组? - How to group an array of objects in JavaScript on specific fields using Lodash? 如何在JavaScript中使用特定键对对象进行分组 - How to group objects with specific key in javaScript
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM