0

I have an array of objects similar to the below:

const data = [
{ "name": "Amsterdam", value: 40000, uniqueId: '2432g53122141' },
{ "name": "New York", value: 200000, uniqueId: '24322141' },
{ "name": "Mumbai", value: 5000, uniqueId: '9999' }
]

I want to convert it to the below format using tab separated strings with proper formatting/alignment similar to below.

This is needed to be a string as I will be sending this data to a third party form which accepts only text and no HTML data.

Name         Value      UniqueId
Amsterdam    40000      243253122141
New York     200000     24322141
Mumbai       5000       9999 

How can I achieve the same with proper formatting so that there is no alignment issues as the length of data for each property can vary as can be seen above. Is there any package available?

jonrsharpe
  • 115,751
  • 26
  • 228
  • 437
Teknoville
  • 459
  • 1
  • 7
  • 18
  • 2
    Do you want it to be tab-separated or should it be fixed-width fields? They're not the same thing. – Barmar Jul 21 '22 at 07:22
  • It seems that the OP needs fixed width fields based on the longest text in each field – Mohsen Alyafei Jul 21 '22 at 07:25
  • @Barmar Yes I need fixed width based on text of longest field.Of course as I mentioned I do not want any HTML related solution as that would not be accepted the by the third party form – Teknoville Jul 21 '22 at 07:30
  • 1
    Maybe ```console.table(data, columns)``` helps you with printing the data (not tab seperated) – AG_1380 Jul 21 '22 at 07:32
  • Loop through the array to get the maximum length of each field. Then loop through it again formatting into fields of the appropriate width. – Barmar Jul 21 '22 at 07:32
  • @AG80 How are you going to capture that into a string so you can send it to the third-party form? – Barmar Jul 21 '22 at 07:33
  • You only need to find the max string length of the `name` and `value` strings as the `uniqueId` is always at the end of the output string. – Mohsen Alyafei Jul 21 '22 at 07:41
  • @Barmar Maybe this thread will help: https://stackoverflow.com/a/67859384/12165605 – AG_1380 Jul 21 '22 at 07:42

4 Answers4

4
  • Loop through the array and collect the max length for each property in an object.
  • Then loop through the array -> padEnd the values to the max length for that key -> join them with a \t get each row value. Loop the properties in the same order as maxLength object in case the properties are missing / or are in different order
  • Then join each row with a \n to get the table body.
  • Join the headers and the body with a \n to get the output.

This works for any number of properties, missing properties, properties in different order, null values

const data = [
  { "name": "Amsterdam", value: 40000, uniqueId: '2432g53122141' },
  { "name": "New York", value: 200000, uniqueId: '24322141' },
  { "name": "Mumbai", value: 5000, uniqueId: '9999' }
]

const maxLength = {}

for (const o of data) {
  for (const key in o)
    maxLength[key] = Math.max(maxLength[key] ?? 0, String(o[key] ?? '').length)
}

console.log(maxLength)

const headers = Object.entries(maxLength)
                      .map(([k, length]) => k.padEnd(length))
                      .join("\t")

const rows = data.map(o =>
  Object.entries(maxLength)
        .map(([k, length]) => String(o[k] ?? '').padEnd(length))
        .join('\t')
).join('\n')

console.log( [headers, rows].join('\n') )
adiga
  • 34,372
  • 9
  • 61
  • 83
1

you can do something like this

const data = [
  { "name": "Amsterdam", value: 40000, uniqueId: '2432g53122141' },
  { "name": "New York", value: 200000, uniqueId: '24322141' },
  { "name": "Mumbai", value: 5000, uniqueId: '9999' }
]
const header = Object.keys(data[0])
const rows  = [header, ...data.map(d => Object.values(d))]



const maxLength = Math.max(...rows.flat().map(s => s.toString().length))

const result = rows.map(d => d.map(s => s.toString().padEnd(maxLength, ' ')).join('\t')).join('\n')

console.log(result)
R4ncid
  • 6,944
  • 1
  • 4
  • 18
0

This is just an example of how you could do it. You could read all the attributes of the json and then try to generate the lines. In order to do the identation I took the largest string in the json and use it as an identation length

function tabify(data) {
    var columns=new Set()
    //Get all the colums
    for(var index in data){
      for(var iKey in Object.keys(data[index]))
          columns.add(Object.keys(data[index])[iKey])
    }
    var maxLength = 0
    //Search maxLength
    for (var index in data) {
        columns.forEach((element) => {
            if (maxLength < element.length)
                maxLength = element.length
            if (maxLength < data[index][element].length)
                maxLength = data[index][element].length
        });
    }
    var outText = ""
    //Generate column line
    columns.forEach((element) => {
        outText += element
        outText += Array((maxLength - element.length) + 1).join(" ")
    });

    outText += "\n"

    //Generate the text formated
    for (var index in data) {
        columns.forEach((element) => {
            outText += data[index][element]
            outText += Array((maxLength - (data[index][element].toString()).length) + 1).join(" ")

        });
        outText += "\n"
    }
    return outText

}

let dataJson = [{
        "name": "Amsterdam",
        value: 40000,
        uniqueId: '2432g53122141'
    },
    {
        "name": "New York",
        value: 200000,
        uniqueId: '24322141'
    },
    {
        "name": "Mumbai",
        value: 5000,
        uniqueId: '9999'
    }
]
text = tabify(dataJson)

console.log(text)
0

You can try this code with lodash library

import * as _ from 'lodash';
    
const data = [
   { name: "Amsterdam", value: 40000, uniqueId: '2432g53122141' },
   { name: "New York", value: 200000, uniqueId: '24322141' },
   { name: "Mumbai", value: 5000, uniqueId: '9999' }
];

const header = _.keys(data[0]);
const values = _.map(data, (iterator) => _.values(iterator));
let maxLength = _.max(_.concat(header, ...values).map(iterator => iterator.length));

let result = '';
result += header.map(x => _.padEnd(x, maxLength)).join('\t').concat('\n');
_.map(values, (iterator) => result += iterator.map(x => _.padEnd(x,maxLength)).join('\t').concat('\n'));

console.log(result.trim());
yyater97
  • 1,697
  • 2
  • 9
  • 5