簡體   English   中英

如何使用 javascript 對數組進行分組並對特定鍵求和

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

我的數據如下:

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 }
];

我想 map 它來獲得所有鍵的組合和計數。 因此,我想得到如下內容:

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 }
];

我真的不知道如何開始。

任何幫助,將不勝感激。

更新

我最終做了以下事情:

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)

這里是游樂場。

但是有更好或更快的方法嗎?

您可以使用分組鍵的長度構建二進制模式,並根據組添加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; }

一種不同的方法,首先使用遞歸構建一棵樹,然后從葉子及其路徑屬性中獲取所有總數。

 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; }

這是一種處理方法:

  1. 創建一個 object 具有所有鍵的唯一值(除了計數),我們應該得到:
     {make: [undefined, 'audi'], fuel: [undefined, 'gasoline', 'diesel'], model: [undefined, 'a1', 'a3']}
  2. 創建一個calculateCount function 來計算提供值的計數,例如:
     calculateCount(results, {make: 'audi'}) === 15
  3. 使用一個置換函數,比如這個,從我們在步驟 1 中創建的 object 創建所有可能的組合
  4. 計算每個組合的總和,使用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)

你可以做這樣的事情

 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)

這部分創建鍵值和未定義的所有組合

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

獲得所有組合后,您就可以創建密鑰(我為此使用了JSON.stringify

那么您只需使用密鑰創建一個 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)

最后你擺脫了鍵並使用Object.values返回值

使用此實現,您可以計算具有不同屬性的元素(計數必須存在)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM