Агрегировать объект, в котором значение для каждого ключа является массивом объектов - PullRequest
2 голосов
/ 11 апреля 2020

Я использую Underscore и Loda sh для группировки массива по дате. Пока все работает хорошо, и я получаю объект, в котором значение для каждого ключа представляет собой массив объектов, например:

 {
    "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
      }
    ]
  } 

Я хочу знать, кто является крупнейшим поставщиком по общему количеству для каждый месяц (например, в апреле Sony с двумя разными покупками на общую сумму 900 000 долларов), но я застрял, пытаясь получить доступ и собрать данные. Я знаю, что в Stackoverflow существует множество подобных вопросов, но, что удивительно, мне не удалось найти подобного вопроса с такой структурой данных. Любая помощь будет принята с благодарностью.

Ответы [ 2 ]

1 голос
/ 11 апреля 2020

Вы можете использовать временный объект (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
1 голос
/ 11 апреля 2020

Вы можете объединить map() и 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));

На основе ключей данных мы получаем массив данных компании за каждый месяц и сокращаем объекты, накапливая их итоги, если поставщик уже существует. Затем мы сопоставляем и сокращаем результирующие данные, сравнивая, какие из них имели наибольшее общее количество, а затем просто сопоставляем конечный результат, чтобы получить имя поставщика.

Крайний случай: У меня есть также заметил небольшую проблему с этим подходом, когда два провайдера имеют одинаковую общую сумму, поэтому я сделал небольшой фрагмент, который будет просто возвращать массив массивов провайдеров, которые так и имеют та же сумма Если мы не примем это во внимание, мы можем вернуть всего одного из крупнейших провайдеров:

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);
...