简体   繁体   中英

Mapping array of objects to array of arrays with headers using ES6

I want to map an array of objects, which I got from a json response of my backend, to an array of arrays, with the first row being an array of headers (titles). I'll use this array to make it downloadable in a csv file.

Also, I want to keep away a couple of headers / columns that are not really interesting for the end user to have in their csv file.

My code is working fine, but I have the idea that it can be done with more concise code. I'm fine with using ES6 / ES2015, but not really experienced with spread syntax and other ES6 goodies myself, so any suggestions for a better, more modern (functional / reactive?) approach are greatly appreciated.

 const originalData = [ {name: 'Gizmo', species: 'cat', age: '9', raw: 'G9e76rd', updated_at: '1318874398806', skill: 'sleeping'}, {name: 'Benny', species: 'dog', age: '3', raw: '98HDo2h', updated_at: '1318874392417', skill: 'chasing tail'}, {name: 'Oscar', species: 'cat', age: '2', raw: '9da8Ro1', updated_at: '1318874390283', skill: 'meowing'} ] let headers = [] const firstRow = originalData[0] for (var key in firstRow) { if (firstRow.hasOwnProperty(key)) { if (!['raw','updated_at'].includes(key)) { headers.push(key) } } } const d = originalData.map(function(_, i) { return headers.map(function(header) { return originalData[i][header] }.bind(this)) }.bind(this)) const result = [headers].concat(d) console.log(result) 

Something like this?

const originalData = [
  { name: 'Gizmo', species: 'cat', age: '9', raw: 'G9e76rd', updated_at: '1318874398806', skill: 'sleeping' },
  { name: 'Benny', species: 'dog', age: '3', raw: '98HDo2h', updated_at: '1318874392417', skill: 'chasing tail' },
  { name: 'Oscar', species: 'cat', age: '2', raw: '9da8Ro1', updated_at: '1318874390283', skill: 'meowing' }
]

const headers = Object.keys(originalData[0]).filter(key => !['raw', 'updated_at'].includes(key));
const d = originalData.map(obj => headers.map(key => obj[key]))
const result = [headers, ...d];

console.log(result)

Basically you could use a closure over the filtered keys and map and concat the arrays.

 const fn = (array => (keys => [keys].concat(array.map(o => keys.map(k => o[k])))) (Object.keys(array[0]).filter(k => !['raw','updated_at'].includes(k)))), data = [{ name: 'Gizmo', species: 'cat', age: '9', raw: 'G9e76rd', updated_at: '1318874398806', skill: 'sleeping' }, { name: 'Benny', species: 'dog', age: '3', raw: '98HDo2h', updated_at: '1318874392417', skill: 'chasing tail' }, { name: 'Oscar', species: 'cat', age: '2', raw: '9da8Ro1', updated_at: '1318874390283', skill: 'meowing' }], result = fn(data); console.log(result); 
 .as-console-wrapper { max-height: 100% !important; top: 0; } 

Yours is good. You could simplify the header creation by using Object.keys

const originalData = [
  {name: 'Gizmo', species: 'cat', age: '9', raw: 'G9e76rd', updated_at: '1318874398806', skill: 'sleeping'},
  {name: 'Benny', species: 'dog', age: '3', raw: '98HDo2h', updated_at: '1318874392417', skill: 'chasing tail'},
  {name: 'Oscar', species: 'cat', age: '2', raw: '9da8Ro1', updated_at: '1318874390283', skill: 'meowing'}
]

const headers = Object.keys(originalData[0])
    .filter(key => !['raw','updated_at'].includes(key)));  
const data = originalData.map(row => headers.map(header => row[header]));

console.log(headers, data);
const originalData = [
  {name: 'Gizmo', species: 'cat', age: '9', raw: 'G9e76rd', updated_at: '1318874398806', skill: 'sleeping'},
  {name: 'Benny', species: 'dog', age: '3', raw: '98HDo2h', updated_at: '1318874392417', skill: 'chasing tail'},
  {name: 'Oscar', species: 'cat', age: '2', raw: '9da8Ro1', updated_at: '1318874390283', skill: 'meowing'}
];

const propertiesNeeded = Object.keys(originalData[0]).filter(prop => !['raw', 'updated_at'].includes(prop));
const dataMapped = originalData.map(obj => propertiesNeeded.map(prop => obj[prop]));
const finalArr = [propertiesNeeded, ...dataMapped];

Try with Array#map used for recreate the array with Object.key and value . and new Set() method user for create the key set value .ignore the repeated one ... its spread syntax

 const originalData = [ {name: 'Gizmo', species: 'cat', age: '9', raw: 'G9e76rd', updated_at: '1318874398806', skill: 'sleeping'}, {name: 'Benny', species: 'dog', age: '3', raw: '98HDo2h', updated_at: '1318874392417', skill: 'chasing tail'}, {name: 'Oscar', species: 'cat', age: '2', raw: '9da8Ro1', updated_at: '1318874390283', skill: 'meowing'} ] var result = [[...new Set(...originalData.map(a=> Object.keys(a)))]].concat(originalData.map(a=> Object.values(a))) console.log(result) 
 .as-console-wrapper { max-height: 100% !important; top: 0; } 

This is how I'd do it. I figured if you know which keys you're after then we can make good use of that.

const data = [
  {name: 'Gizmo', species: 'cat', age: '9', raw: 'G9e76rd', updated_at: '1318874398806', skill: 'sleeping'},
  {name: 'Benny', species: 'dog', age: '3', raw: '98HDo2h', updated_at: '1318874392417', skill: 'chasing tail'},
  {name: 'Oscar', species: 'cat', age: '2', raw: '9da8Ro1', updated_at: '1318874390283', skill: 'meowing'}
]

const desiredKeys = ['name', 'species', 'age', 'skill']

const result = [desiredKeys].concat(data.map(pet => desiredKeys.map(key => pet[key])))

console.log(result)

I'd like to point out that an object's keys order is not entirely "fixed" by spec.

If your first animal in your originalData starts with a species property, your whole table will be formatted in that column order...

Therefore I'd advice you to explicitly define your columns in an array, in which order does matter.

Note that in the example below I've swapped the property declaration order of Gizmo. Put this data in your own code and the first column will be species. (at least in my browser it is, I guess it can even differ between browsers?)

 const data = [ {species: 'cat', name: 'Gizmo', age: '9', raw: 'G9e76rd', updated_at: '1318874398806', skill: 'sleeping'}, {name: 'Benny', species: 'dog', age: '3', raw: '98HDo2h', updated_at: '1318874392417', skill: 'chasing tail'}, {name: 'Oscar', species: 'cat', age: '2', raw: '9da8Ro1', updated_at: '1318874390283', skill: 'meowing'} ] const getProps = props => obj => props.map(k => obj[k]); const columns = ["name", "species", "age", "skill"]; console.log( [columns, ...data.map(getProps(columns))] ); 

A single line of code in an unbroken chain using a filter and reduce.

 var unborken = chain => chain.filter((_, i, xx) => delete xx[i].updated_at && delete xx[i].raw).reduce((aac, _, i, aa) => (i === 0 ? aac.push(Object.keys(aa[i])) && aac.push(Object.values(aa[i])) : aac.push(Object.values(aa[i])), aac), []); const originalData = [{ name: 'Gizmo', species: 'cat', age: '9', raw: 'G9e76rd', updated_at: '1318874398806', skill: 'sleeping' }, { name: 'Benny', species: 'dog', age: '3', raw: '98HDo2h', updated_at: '1318874392417', skill: 'chasing tail' }, { name: 'Oscar', species: 'cat', age: '2', raw: '9da8Ro1', updated_at: '1318874390283', skill: 'meowing' } ]; console.log(unborken(originalData)); 
 .as-console-wrapper { max-height: 100% !important; top: 0; } 

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM