Pivot/Transform json 个数据列以在 javascript 中创建新行

Pivot/Transform json data columns to create new rows in javascript

我有一个 json 文件,格式如下:

const data = [
   {category: "A", country: "UK", name: "United Kingdom", country_id: "01", 2015: 5, 2016: 56, 2017: 10},
   {category: "B", country: "UK", name: "United Kingdom", country_id: "01", 2015: 4, 2016: 10, 2017: 10},
   {category: "C", country: "UK", name: "United Kingdom", country_id: "01", 2015: 10, 2016: 7, 2017: 45},
   {category: "A", country: "PO", name: "Poland", country_id: "02", 2015: 9, 2016: 14, 2017: 10},
   {category: "B", country: "PO", name: "Poland", country_id: "02", 2015: 10, 2016: 40, 2017: 0},
   {category: "C", country: "PO", name: "Poland", country_id: "02", 2015: 60, 2016: 30, 2017: 74},
   {category: "A", country: "CZ", name: "Czech Republic", country_id: "03", 2015: 30, 2016: 20, 2017: 10},
   {category: "B", country: "CZ", name: "Czech Republic", country_id: "03", 2015: 15, 2016: 28, 2017: 1},
   {category: "C", country: "CZ", name: "Czech Republic", country_id: "03", 2015: 16, 2016: 10, 2017: 2}
  ]

我想旋转数据以获得以下格式:

const data = [
   {country: "UK", name: "United Kingdom", country_id: "01", year: "2015", "a": 5 , "b": 4, "c": 10},
   {country: "UK", name: "United Kingdom", country_id: "01", year: "2016", "a": 56 , "b": 10, "c": 7},
   {country: "UK", name: "United Kingdom", country_id: "01", year: "2017", "a": 10 , "b": 10, "c": 45},
   {country: "PO", name: "Poland", country_id: "02", year: "2015", "a": 9 , "b": 10, "c": 80},
   {country: "PO", name: "Poland", country_id: "02", year: "2016", "a": 14 , "b": 40, "c": 30},
   {country: "PO", name: "Poland", country_id: "02", year: "2017", "a": 10 , "b": 0, "c": 74},
   {country: "CZ", name: "Czech Republic", country_id: "03", year: "2015", "a": 30 , "b": 15, "c": 16},
   {country: "CZ", name: "Czech Republic", country_id: "03", year: "2016", "a": 20 , "b": 28, "c": 1},
   {country: "CZ", name: "Czech Republic", country_id: "03", year: "2017", "a": 10 , "b": 1, "c": 2}

我尝试在 map 方法中编写 for 循环,但无法创建 abc 属性。

这不是最好的解决方案,但可以。同时,我为重复项做了一个解决方法。如果其他年份会有新数据,您可以使用 ...rest 参数来初始化年份数组。

let newData = [];
let countries = data.map(({country})=> country)
let categories = data.map(({category})=> category)
let years = [2015,2016,2017];

countries.forEach(country => {
    let countryData = data.filter(({country:c}) => c==country);
    let yearData = {2015:{},2016:{},2017:{}};
    years.forEach(year => {
        categories.forEach(category => {
            yearData[year][category] = countryData.find(({category:cat}) => cat==category)[year]
       })
   })
   let {name,country_id}= data.find(({country:c}) => c == country);

   Object.entries(yearData).forEach(([year,categories]) => {
        newData.push({country,name,country_id,year, ...categories})
   })
   newData = newData.filter((data,i) => i%9<3)
   console.log(newData)
})

旋转是在评论的 3 行上完成的 'Rotation'

为了能够做到这一点,我们需要能够访问原始数据集的多行。这里的策略让我们能够做到这一点。

第 1 步。获取唯一 country_ids、年份和类别的列表

有几种方法可以做到这一点,我展示了最容易理解的方法,即转换为Set(自动删除重复项),然后返回到数组以方便使用.

第 2 步。从简单数组移动到对象

行不是简单地按顺序排列 0...8,而是我们现在将它们放在 3x3 网格中,可按国家和类别寻址。

第 3 步。构建所需的输出

现在在每个国家/地区内,我们可以通过从原始数据的三个不同类别中“提取”今年的值来提取选定年份的所有数据。

const data = [
   {category: "A", country: "UK", name: "United Kingdom", country_id: "01", 2015: 5, 2016: 56, 2017: 10},
   {category: "B", country: "UK", name: "United Kingdom", country_id: "01", 2015: 4, 2016: 10, 2017: 10},
   {category: "C", country: "UK", name: "United Kingdom", country_id: "01", 2015: 10, 2016: 7, 2017: 45},
   {category: "A", country: "PO", name: "Poland", country_id: "02", 2015: 9, 2016: 14, 2017: 10},
   {category: "B", country: "PO", name: "Poland", country_id: "02", 2015: 10, 2016: 40, 2017: 0},
   {category: "C", country: "PO", name: "Poland", country_id: "02", 2015: 60, 2016: 30, 2017: 74},
   {category: "A", country: "CZ", name: "Czech Republic", country_id: "03", 2015: 30, 2016: 20, 2017: 10},
   {category: "B", country: "CZ", name: "Czech Republic", country_id: "03", 2015: 15, 2016: 28, 2017: 1},
   {category: "C", country: "CZ", name: "Czech Republic", country_id: "03", 2015: 16, 2016: 10, 2017: 2}
  ]


// Step 1. Extract the unique country_id, category Ids and years

const country_ids = Array(...new Set(data.map((x) => x.country_id)));
const categories = Array(...new Set(data.map((x) => x.category)));
const years = ["2015","2016","2017"];

// Step 2. Convert the source data into an object so that you can conveniently read off particular rows, in terms of COUNTRY_ID and CATEGORY

const sourceRows = {};
data.forEach((row) => {
  if (!sourceRows[row.country_id]) {
    sourceRows[row.country_id] = {};
  }
  sourceRows[row.country_id][row.category] = row;
});

// You can visualise the output here with this, if you want:
//     console.log(sourceRows)


// Step 3. Create destination array, and poke a row into it for each country & year.

const destination = [];
country_ids.forEach((country_id) => {
  years.forEach((year) => {
    const sourceRow = sourceRows[country_id][categories[0]];
    const destRow = {
      country_id: country_id,
      name: sourceRow.name,
      country: sourceRow.country,
      year: year,
      a: sourceRows[country_id]["A"][year], // Rotation
      b: sourceRows[country_id]["B"][year], // Rotation
      c: sourceRows[country_id]["C"][year]  // Rotation
    };
    destination.push(destRow);
  });
});

console.log(destination);