聚合一个对象,其中每个键的值是一个对象数组

Aggregate an object in which the value for each key is an array of objects

我正在使用 Underscore 和 Lodash 按日期对数组进行分组。到目前为止一切正常,我得到一个对象,其中每个键的值都是一个对象数组,如下所示:

 {
    "april": [
      {
        "quantity": "200",
        "date": "05/04/2020, 23:43",
        "price": "150",
        "product": "Washing Machine",
        "provider": "LG",
        "total": 30000
      },
      {
        "quantity": "1000",
        "date": "10/04/2020, 00:35",
        "price": "800",
        "product": "Television",
        "provider": "Samsung",
        "total": 800000
      },
      {
        "quantity": "3000",
        "date": "10/04/2020, 18:02",
        "price": "2",
        "product": "Computer",
        "provider": "Sony",
        "total": 600000
      },
      {
        "quantity": "1000",
        "date": "10/04/2020, 18:03",
        "price": "300",
        "product": "Bluetooth Speaker",
        "provider": "Sony",
        "total": 300000
      }
    ],
    "march": [
      {
        "quantity": "400",
        "date": "18/03/2020, 23:47",
        "price": "230",
        "product": "Home Theatre",
        "provider": "Bose",
        "total": 92000
      }
    ],
    "february": [
      {
        "quantity": "550",
        "date": "07/02/2020, 23:52",
        "price": "300",
        "product": "Printer",
        "provider": "Epson",
        "total": 165000
      },
      {
        "quantity": "750",
        "date": "07/02/2020, 23:52",
        "price": "200",
        "product": "Television",
        "provider": "Panasonic",
        "total": 150000
      }
    ]
  } 

我想知道谁是每个月总计最大的供应商(例如,4 月份是索尼,两次不同的采购总额为 900,000 美元),但我一直无法访问和汇总数据。我知道 Whosebug 中有很多类似的问题,但令人惊讶的是我无法找到与这种数据结构相关的任何类似问题。 任何帮助将不胜感激。

您可以结合使用 map() and reduce() 来实现您想要的效果,例如:

let data = {
  april: [{
      quantity: "200",
      date: "05/04/2020, 23:43",
      price: "150",
      product: "Washing Machine",
      provider: "LG",
      total: 30000,
    },
    {
      quantity: "1000",
      date: "10/04/2020, 00:35",
      price: "800",
      product: "Television",
      provider: "Samsung",
      total: 800000,
    },
    {
      quantity: "3000",
      date: "10/04/2020, 18:02",
      price: "2",
      product: "Computer",
      provider: "Sony",
      total: 600000,
    },
    {
      quantity: "1000",
      date: "10/04/2020, 18:03",
      price: "300",
      product: "Bluetooth Speaker",
      provider: "Sony",
      total: 300000,
    },
  ],
  march: [{
    quantity: "400",
    date: "18/03/2020, 23:47",
    price: "230",
    product: "Home Theatre",
    provider: "Bose",
    total: 92000,
  }, ],
  february: [{
      quantity: "550",
      date: "07/02/2020, 23:52",
      price: "300",
      product: "Printer",
      provider: "Epson",
      total: 165000,
    },
    {
      quantity: "750",
      date: "07/02/2020, 23:52",
      price: "200",
      product: "Television",
      provider: "Panasonic",
      total: 150000,
    },
  ],
};

let aggregatedData = Object.keys(data).map((month) =>
  data[month].reduce((acc, current, i) => {
    let existing = acc.find((o) => o.provider === current.provider);
    if (existing) {
      existing.total += current.total;
    } else {
      acc[i] = { provider: current.provider, total: current.total };
    }
    return acc;
  }, [])
);

let biggestProviders = aggregatedData.map((data) =>
  data.reduce((p, c) => (c.total > p.total ? c : p))
);

console.log(biggestProviders);
console.log(biggestProviders.map(o => o.provider));

根据数据的键,我们获取每个月的公司数据数组并减少对象,如果提供者已经存在则累加它们的总数。然后我们通过比较谁的总数最高来映射和减少结果数据,然后我们只映射最终结果以获得提供者的名称。

边缘情况: 我还注意到这种方法的一个小问题,即在有两个提供商的总数完全相同的情况下,所以我已经制作了一个快速片段,它只是 return 一组恰好具有相同总数的提供者数组。如果我们不考虑这一点,我们可能 return 只是最大的提供商之一,总计:

let data = {
  april: [{
      quantity: "200",
      date: "05/04/2020, 23:43",
      price: "150",
      product: "Washing Machine",
      provider: "LG",
      total: 30000,
    },
    {
      quantity: "1000",
      date: "10/04/2020, 00:35",
      price: "800",
      product: "Television",
      provider: "Samsung",
      total: 900000,
    },
    {
      quantity: "3000",
      date: "10/04/2020, 18:02",
      price: "2",
      product: "Computer",
      provider: "Sony",
      total: 600000,
    },
    {
      quantity: "1000",
      date: "10/04/2020, 18:03",
      price: "300",
      product: "Bluetooth Speaker",
      provider: "Sony",
      total: 300000,
    },
  ],
  march: [{
    quantity: "400",
    date: "18/03/2020, 23:47",
    price: "230",
    product: "Home Theatre",
    provider: "Bose",
    total: 92000,
  }, ],
  february: [{
      quantity: "550",
      date: "07/02/2020, 23:52",
      price: "300",
      product: "Printer",
      provider: "Epson",
      total: 165000,
    },
    {
      quantity: "750",
      date: "07/02/2020, 23:52",
      price: "200",
      product: "Television",
      provider: "Panasonic",
      total: 165000,
    },
  ],
};

let aggregatedData = Object.keys(data).map((month) =>
  data[month].reduce((acc, current, i) => {
    let existing = acc.find((o) => o.provider === current.provider);
    if (existing) {
      existing.total += current.total;
    } else {
      acc[i] = {
        provider: current.provider,
        total: current.total
      };
    }
    return acc;
  }, [])
);

let biggestProviders = aggregatedData.map((data) =>
  data.reduce((p, c) => {
    if (p.length === 0) return p.concat(c);

    if (c.total === p[0].total) {
      p.push(c);
    } else {
      p = c.total > p[0].total ? Array.of(c) : Array.of(...p);
    }
    return p;
  }, [])
);

console.log(biggestProviders);

您可以使用临时对象(下面的 resultObj)在遍历列表时累计每个提供商每月的总数。

跟踪每月最高总价的对象示例:

var resultObj = {
    "max" : {
        "num" : 0,          // current max total goes here
        "provider" : ""     // provider with max total goes here
    },
    "maxObject" : {},       // max items for each month stored here
    getMax : function() {
        // returns current max object to be added to maxObject[month]
        return { "provider": this.max.provider,  "total": this.max.num };    
    },
    "reset" : function() {      // reset max
        this.max.num = 0;
        this.max.provider = ""
    },
    "createKey" : function(month) {     // create month key
        if(!this.hasOwnProperty(month))
            this[month] = {};
    }
};

以及遍历对象数组的函数:

function getMaxValue() {
  for(let month in obj) {               // for each month in the object
    resultObj.reset();                  // reset max
    resultObj.createKey(month);         // create key for month in resultObj
    obj[month].forEach(function(el) {   // for each object within month
      if(resultObj[month][el.provider]) {      // if the provider exists as a key
        resultObj[month][el.provider] += el.total;
      } else {                                 // provider doesn't yet exist
        resultObj[month][el.provider] = el.total;
      }

      // if current total is greater than current max (for given month)
      if(resultObj[month][el.provider] > resultObj.max.num) {
        resultObj.max.num = resultObj[month][el.provider];
        resultObj.max.provider = el.provider;
      }
    });
    resultObj.maxObject[month] = resultObj.getMax();  // generate result for month
 }
    return resultObj.maxObject;    // return the result object
}

检查并测试如下:

var obj = {
    "april": [
    {
      "quantity": "200",
      "date": "05/04/2020, 23:43",
      "price": "150",
      "product": "Washing Machine",
      "provider": "LG",
      "total": 30000
    },
    {
      "quantity": "1000",
      "date": "10/04/2020, 00:35",
      "price": "800",
      "product": "Television",
      "provider": "Samsung",
      "total": 800000
    },
    {
      "quantity": "3000",
      "date": "10/04/2020, 18:02",
      "price": "2",
      "product": "Computer",
      "provider": "Sony",
      "total": 600000
    },
    {
      "quantity": "1000",
      "date": "10/04/2020, 18:03",
      "price": "300",
      "product": "Bluetooth Speaker",
      "provider": "Sony",
      "total": 300000
    }
  ],
  "march": [
    {
      "quantity": "400",
      "date": "18/03/2020, 23:47",
      "price": "230",
      "product": "Home Theatre",
      "provider": "Bose",
      "total": 92000
    }
  ],
  "february": [
    {
      "quantity": "550",
      "date": "07/02/2020, 23:52",
      "price": "300",
      "product": "Printer",
      "provider": "Epson",
      "total": 165000
    },
    {
      "quantity": "750",
      "date": "07/02/2020, 23:52",
      "price": "200",
      "product": "Television",
      "provider": "Panasonic",
      "total": 150000
    }
   ]
};
  
var resultObj = {
  "max" : {
    "num" : 0,
    "provider" : ""
  },
  "maxObject" : {},
  "getMax" : function() {
    return { "provider": this.max.provider,  "total": this.max.num };
  },
  "reset" : function() {
      this.max.num = 0;
      this.max.provider = "";
  },
  "createKey" : function(month) {
    if(!this.hasOwnProperty(month))
      this[month] = {};
  }
};
  
function getMaxValue() {
  for(let month in obj) {
    resultObj.reset();
    resultObj.createKey(month);
    obj[month].forEach(function(el) {
      if(resultObj[month][el.provider]) {
        resultObj[month][el.provider] += el.total;
      } else {
        resultObj[month][el.provider] = el.total;
      }

      if(resultObj[month][el.provider] > resultObj.max.num) {
        resultObj.max.num = resultObj[month][el.provider];
        resultObj.max.provider = el.provider;
      }
    });
    resultObj.maxObject[month] = resultObj.getMax();
 }
    return resultObj.maxObject;
}

var maxValues = getMaxValue();     // receives an object
console.log( maxValues );          // prints the all the results
console.log("\nmax for April:");    
console.log( maxValues.april );      // prints results for April

console.log("\nNow to check resultObj:");
console.log( resultObj );          // prints the whole temp object