Транспонирование данных JSON в Javascript

#javascript

Вопрос:

Я пытаюсь перенести результат запроса в матрицу. По сути, если бы у меня был такой результат:

Атрибут1 Вэл Рассчитывать
Яблоки Вал 1 100
Бананы Вал 1 200
Яблоки Вал 2 300
Бананы Вал 2 400

Я хочу перенести это на это:

Атрибут1 Вал 1 Вал 2
Яблоки 100 300
Бананы 200 400

Однако количество значений в поле атрибута и поле Val являются динамическими. Как бы я, следовательно, перенес это в JS, чтобы мой выходной массив JSON представлял собой динамическую структуру, зависящую от результата запроса?

У меня есть фрагмент кода ниже, где я перечислил различные [Attribute1] и [Val], но как мне построить массив json, в котором определение является динамическим? Я сделал попытку в конце концов, но я знаю, что это еще не правильно…

 var res = [{
    "Attribute1": 'Apples',
    "Val": 'Val 1',
    "Count": 100
  },
  {
    "Attribute1": 'Bananas',
    "Val": 'Val 1',
    "Count": 200
  },
  {
    "Attribute1": 'Apples',
    "Val": 'Val 2',
    "Count": 300
  },
  {
    "Attribute1": 'Bananas',
    "Val": 'Val 2',
    "Count": 400
  }
]


const y_result = [];
const map = new Map();
for (const item of res) {
  if (!map.has(item.Attribute1)) {
    map.set(item.Attribute1, true); // set any value to Map
    y_result.push({
      Attribute1: item.Attribute1,
    });
  }
}
console.log(y_result)

const x_result = [];
const x_map = new Map();
for (const item of res) {
  if (!x_map.has(item.Val)) {
    x_map.set(item.Val, true); // set any value to Map
    x_result.push({
      Attribute1: item.Val,
    });
  }
}
console.log(x_result)

let tmp
let new_res

console.log(y_result[0].Attribute1)
for (const item of y_result) {
    tmp = { y_result[0].Attribute1 : item.Count };
  new_res.push(tmp)
}
console.log(new_res)
 

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

1. вау, еще 2 отличных ответа, пока я писал свой 🙂 голосую за оба! 🙂

Ответ №1:

таким образом..

 const res = 
  [ { Attribute1: 'Apples',  Val: 'Val 1', Count: 100 } 
  , { Attribute1: 'Bananas', Val: 'Val 1', Count: 200 } 
  , { Attribute1: 'Apples',  Val: 'Val 2', Count: 300 } 
  , { Attribute1: 'Bananas', Val: 'Val 2', Count: 400 } 
  ] 

const y_result = Object.entries(res.reduce((a,{Attribute1,Val,Count})=>
    {
    a[Attribute1]      = a[Attribute1] ?? {}
    a[Attribute1][Val] = Count
    return a
    },{})).map(([Attribute1,vals])=>({Attribute1, ...vals}))
    
console.log( y_result ) 
 .as-console-wrapper { max-height: 100% !important; top: 0 } 

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

1. Мило! Мой подход состоял в том, чтобы использовать глобальную переменную, вы избегаете этого, создавая объект, а затем map записываете его записи в массив, любите его.

Ответ №2:

Мой подход, используя некоторые destructuring , и. Array#forEach

  • Просмотрите каждый элемент в массиве
  • Проверьте его Attribute1 значение и проверьте, видели ли его раньше.
  • Если он прочитал Val свойство, добавьте его в существующий объект
  • Если объект не создан, прочитайте Val свойство и установите его.

Код:

 var res = [
    { Attribute1: "Apples", Val: "Val 1", Count: 100  },
    { Attribute1: "Bananas", Val: "Val 1", Count: 200 },
    { Attribute1: "Apples", Val: "Val 2", Count: 300  },
    { Attribute1: "Bananas", Val: "Val 2", Count: 400 },
];

let result = [], seenBefore = [];

res.forEach(({ Attribute1, Count, Val }) => {
    let foundHere = seenBefore.indexOf(Attribute1)
    
    if (foundHere !== -1){
      result[foundHere][Val] = Count;
    }
    else {
      result.push({ Attribute1, [Val]: Count });
      seenBefore.push(Attribute1)
    }
}) 

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

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

1. Совсем неплохо 🙂

2. Спасибо вам за вашу помощь — тоже хороший подход.

Ответ №3:

Это то, что вы ищете?

Приведенный ниже фрагмент выполняет эту работу в 2 этапа: сначала значение Val становится ключом и принимает значение Count как свое собственное значение, а затем объединяет все значения вместе. Второй шаг выполняется с помощью registry объекта, который позволяет добавить все ключи, которых нет Attribute1 , в уже существующую запись, если она была предварительно записана там.

 const res = [
  {
    Attribute1: 'Apples',
    Val: 'Val 1',
    Count: 100,
  },
  {
    Attribute1: 'Bananas',
    Val: 'Val 1',
    Count: 200,
  },
  {
    Attribute1: 'Apples',
    Val: 'Val 2',
    Count: 300,
  },
  {
    Attribute1: 'Bananas',
    Val: 'Val 2',
    Count: 400,
  },
];

const registry = {};

const result = res
  .map(
    ({ Attribute1, Val, Count }) => ({
      Attribute1,
      [Val]: Count,
    }),
    []
  )
  .reduce((acc, row, i) => {
    const at = row.Attribute1;

    if (!(at in registry)) {
      registry[at] = i;
      acc.push(row);
      return acc;
    }

    Object.entries(row).forEach(([key, value]) => {
      if (key !== 'Attribute1') {
        acc[registry[at]][key] = value;
      }
    });

    return acc;
  }, []);

console.log(result);