Как сжать и переназначить данные массива в Javascript - PullRequest
0 голосов
/ 04 марта 2020

У меня есть этот массив данных, и мне нужна его переназначенная версия для итерации по датам.

var objArr = [
     {"Country": "US", "2017-07-12": "1", "2017-07-13": "2"},
     {"Country": "US", "2017-07-12": "2", "2017-07-13": "2"},
     {"Country": "CN",  "2017-07-12": "5", "2017-07-13": "7"},
     {"Country": "CN", "2017-07-12": "5", "2017-07-13": "7"}
   ]
  • Страны должны суммировать свои значения и не должны появляться дважды во внутреннем массиве.
  • В конце я хочу получить массив, подобный этому:
     var remapped = [
       {"2017-07-12": [
                    {"Country: "US", "value": 3}, 
                    {"Country: "CN", "value": 10}],
       {"2017-07-13": [
                    {"Country: "US", "value": 4},
                    {"Country: "US", "value": 14}]
     ]

В моем текущем случае я получаю это, но страны должны быть уменьшены, а значение суммировано:

var remapped = [
   {"2017-07-12": [
                {"Country: "US", "value": 1}, 
                {"Country: "US", "value": 2}, 
                {"Country: "CN", "value": 5}],
                {"Country: "CN", "value": 5}
                  ],
   {"2017-07-13": [
                {"Country: "US", "value": 2},
                {"Country: "US", "value": 2},
                {"Country: "US", "value": 7}
                {"Country: "US", "value": 7}
                 ]
 ]

Это то, что я до сих пор. Но для меня это кажется слишком сложным, и я уверен, что есть гораздо более эффективный способ решить это: в этом штате у меня есть страны, переназначенные на даты, но я не уверен, как их «сократить». Мне действительно нужно несколько итераций по массивам?

const res = [];
dateArray.forEach(date => (objArr[date] = [])); // I create an array with dates which could contain another array

objArr.forEach(item => {
  dates.forEach(date => {
    res[date].push({
      Country: item['Country'],
      value: item[date],
    });
  });
});

Ответы [ 3 ]

0 голосов
/ 04 марта 2020

Вы можете взять вспомогательный объект для ссылок на объекты и перебрать пары ключ / значение заданных данных.

var data = [{ Country: "US", "2017-07-12": "1", "2017-07-13": "2" }, { Country: "US", "2017-07-12": "2", "2017-07-13": "2" }, { Country: "CN", "2017-07-12": "5", "2017-07-13": "7" }, { Country: "CN", "2017-07-12": "5", "2017-07-13": "7" }],
    reference = {},
    result = data.reduce((r, { Country, ...o }) => {
        Object.entries(o).forEach(([k, v]) => {
            if (!reference[k]) {
                reference[k] = { _: [] };
                r.push({ [k]: reference[k]._ });
            }
            if (!reference[k][Country]) {
                reference[k]._.push(reference[k][Country] = { Country, value: 0 });
            }
            reference[k][Country].value += +v;
        });
        return r;
    }, []);

console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
0 голосов
/ 04 марта 2020

Вот еще один подход:

const extractDates = objArr => Object .entries (objArr .reduce (
  (a, {Country, ...rest}) => Object .entries (rest) .reduce ((a, [date, val]) => ({
    ...a,
    [date]: {...a [date], [Country]: ((a [date] || {}) [Country] || 0) + Number (val)}
  }), a),
  {}
)) .map (([d, o]) => ({[d]: Object .entries (o) .map (([k, v]) => ({Country: k, value: v}))}))

const objArr = [{"Country": "US", "2017-07-12": "1", "2017-07-13": "2"}, {"Country": "US", "2017-07-12": "2", "2017-07-13": "2"}, {"Country": "CN",  "2017-07-12": "5", "2017-07-13": "7"}, {"Country": "CN", "2017-07-12": "5", "2017-07-13": "7"}]

console .log (extractDates (objArr))
.as-console-wrapper {max-height: 100% !important; top: 0}

Это дает результат, который вы просили в вопросе, массив элементов с одним ключом. Но обратите внимание, что он построен вокруг этого ядра:

objArr .reduce (
  (a, {Country, ... rest}) => Object .entries (rest) .reduce ((a, [date, val]) => ({
    ...a,
    [date]: {... a [date], [Country]: ((a [date] || {}) [Country] || 0) + Number (val)} 
  }), a),
  {}
)

, что дает мне гораздо более полезную структуру данных:

{
  "2017-07-12": {CN: 10, US: 3}, 
  "2017-07-13": {CN: 14, US: 4}
}

В то время как окончательная структура (без Object .entries (...) .map (...) обертку) можно построить за один проход (см., например, ответ Нины; ответ от Nenand Vracar дает несколько иную структуру, я нахожу этот очиститель пробоя и считаю, что промежуточный формат в большинстве случаев будет проще использовать.

0 голосов
/ 04 марта 2020

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

var data = [
 {"Country": "US", "2017-07-12": "1", "2017-07-13": "2"},
 {"Country": "US", "2017-07-12": "2", "2017-07-13": "2"},
 {"Country": "CN",  "2017-07-12": "5", "2017-07-13": "7"},
 {"Country": "CN", "2017-07-12": "5", "2017-07-13": "7"}
]

const result = data.reduce((r, {Country, ...rest}, i) => {
  Object.entries(rest).forEach(([k, v]) => {
    if(!r[k]) r[k] = {}
    if(!r[k][Country]) r[k][Country] = {Country, value: +v}
    else r[k][Country].value += +v
  })
  
  return r;
}, {})

for(let i in result) {
  result[i] = Object.values(result[i])
}

console.log(result)
...