Как суммировать, если имя и дата совпадают с двумя данными API JSON?

#javascript #jquery

#javascript #jquery

Вопрос:

Есть два запроса / URL API

Это первый URL-адрес запроса API и данные, поступающие из

      http://127.0.0.1:8000/api/onlineUserData

                   {"onlineUserData":[
                      ["Month"  , "Amania"   , "Shyral" , "Dorpan"],
                      ["Nov-16" ,    9       ,   11     ,    6    ] ,
                      ["Nov-18" ,    5       ,   0      ,    0    ]
                    ]};
  

Это второй URL-адрес запроса API и данные, поступающие из

      http://127.0.0.1:8000/api/offlineUserData

                   {"offlineUserData":[
                      ["Month"  , "Amania" , "Shyral" , "Diskhant"],
                      ["Nov-16" ,    4     ,    7     ,     0     ], 
                      ["Nov-20" ,    12    ,    8     ,     9     ], 
                    ]};
  

Теперь я хочу суммировать два JSON-данных, если их имя пользователя и месяц / дата совпадают между двумя данными API

   {"AllUser":[
      [" Month"   , "Amania" , "Shyral" , "Dorpan","Diskhant" ],
      [" Nov-16"  ,  13      ,   18     ,    6    ,    0      ], 
      [" Nov-18 " ,  5       ,    0     ,    0    ,    0       ],
      [" Nov-20 " ,  12      ,    8     ,    0    ,    9      ],           ]
   ] 
  

Комментарии:

1. Привет, Саурав, и добро пожаловать в SO. Есть ли особая причина, по которой ваши данные структурированы как вложенный массив? И если нет, можете ли вы преобразовать свои данные в объектную форму, например: [{ date: '2019-11-16', "Amania": 9, "Shyral": 11, "Dorphan": 6 }, { ... }] . Это значительно упростит объединение, добавление и различие и сделает ваши данные более значимыми.

2. Данные @EmielZuurbier отправляются таким образом, хотя служат. Они отправили этот формат JSON для использования в диаграмме Google. Мне просто нужно суммировать два JSON-данных.Так

Ответ №1:

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

Для этого данные необходимо преобразовать в структуру с ключами и значениями. Это дает каждому значению имя и значение того, что это такое, а также делает их объединение менее подверженным ошибкам.

 [
  {
    'Month': 'Nov-16',
    'Amania': 9,
    'Shyral': 11,
    'Dorpan': 6
  },
  {
    ...
  },
  ...
];

  

Теперь вам нужно убедиться, что все ваши ключи совпадают, чтобы при начале подсчета у вас были равные наборы данных для подсчета.

Обратите внимание, что это Diskhant было добавлено к объекту ниже. Теперь это имя существует в каждом объекте, и можно вычислить общее его количество.

 [
  {
    'Month': 'Nov-16',
    'Amania': 9,
    'Shyral': 11,
    'Dorpan': 6,
    'Diskhant': 0
  },
  {
    ...
  },
  ...
];
  

Отсюда вы можете объединить два набора в один и начать фильтрацию повторяющихся Month значений. При возникновении такого дублирования добавьте значение текущего объекта и верните результат.

Я действительно считаю, что это можно упростить, но моя попытка заставила меня выполнить все эти вспомогательные функции, чтобы убедиться, что данные обрабатываются правильно. Это также позволяет вам вводить более 2 наборов данных, если вам нужно их объединить.

 const online = {
  "onlineUserData": [
    ["Month", "Amania", "Shyral", "Dorpan"],
    ["Nov-16", 9, 11, 6],
    ["Nov-18", 5, 0, 0]
  ]
};

const offline = {
  "offlineUserData": [
    ["Month", "Amania", "Shyral", "Diskhant"],
    ["Nov-16", 4, 7, 0],
    ["Nov-20", 12, 8, 9],
  ]
};

/**
 * Converts the nested arrays to an array of objects.
 */
const tableToObjects = data => {
  const [ headers, ...entries ] = data;
  return entries.map(entry => entry.reduce((acc, cur, i) => {
    acc[headers[i]] = cur;
    return acc;
  }, {}));
};

/**
 * Converts an array of objects into nested arrays.
 */
const objectsToTable = data => [
  Object.keys(data[0]),
  ...(data.map(entry => Object.values(entry)))
];

/**
 * Returns an array of all keys that are present.
 */
const getKeyMap = data => [...data.reduce((set, entry) => {
  Object.keys(entry).forEach(key => set.add(key));
  return set;
}, new Set())];

/**
 * Modifies the data to ensure that all objects have the
 * same keys. This is necessary to get a correct output
 * when counting and adding up the values of each object.
 */
const equalizeData = data => {
  const keys = getKeyMap(data);
  return data.map(entry => keys.reduce((obj, key) => {
    obj[key] = entry[key] || 0
    return obj;
  }, {}));
}

/**
 * Merges the data by the Month property.
 * If a Month is already present in the array then the values
 * of that object will be added to the existing object.
 */
const mergeData = data => data.reduce((arr, entry) => {
  const { Month, ...rest } = entry;
  const present = arr.find(newEntry => newEntry['Month'] === Month);
  if (present) {
    Object.entries(rest).forEach(([ key, value ]) => {
      present[key] = (present[key] || 0)   value;
    });
  } else {
    arr.push(entry);
  }
  return arr;
}, []);

/**
 * Function that uses all the functions from above to combine
 * the two nested arrays into a single nested array.
 * Returns an object with a single `allUsers` property.
 */
const allUsers = (...dataSets) => {
  const allData = dataSets.flatMap(dataSet => {
    const table = Object.values(dataSet)[0];
    return tableToObjects(table);
  });
  const equalizedData = equalizeData(allData)
  const mergedData = mergeData(equalizedData);
  return {
    'allUsers': objectsToTable(mergedData)
  };
};

// Call the function.
const result = allUsers(online, offline);

// This is just to see the output of the function.
const output = document.getElementById('output');
output.innerHTML = JSON.stringify(result, null, 2);  
 pre {
  display: inline-block;
  background-color: #f7f7f7;
  border: 1px solid #d0d0d0;
  border-radius: 5px;
  padding: 15px;
}  
 <code><pre id="output"></pre></code>  

Комментарии:

1. привет, спасибо за ваш ответ. я просто попробую ваше решение и дам вам ответ