1

if I have an array of strings like:

['person,item,cost,amount',
  'John,shoes,200,2']

how could I convert this into an object that resembles:

{  
   'John':[  
      {  
         item:'shoes',
         cost:'200',
         amount:'2',
         totalPriceForItems:'400'
      }
goatstash
  • 162
  • 8
  • 1
    so, the array is always length 2? with CSV string values – Bravo Mar 25 '22 at 04:09
  • 1
    Where does the `totalPriceForItems: '400'` come from? – Hao Wu Mar 25 '22 at 04:10
  • 400 is just amount * totalPriceForItems it's added in and not in the array @HaoWu – goatstash Mar 25 '22 at 04:12
  • You can use array reduce to create object. – MANOJ MUKHERJEE Mar 25 '22 at 04:19
  • so, `totalPriceForItems` relies on there being a `cost` and `amount` entry ... and the "key" corresponds to the `person` ... so, it should be really easy since 3 of the 4 fields are static, so you barely need to refer to the `[0]` element at all ... unless the *order* can be different - seems like a very odd data format, not useful, not flexible, not simple to use and why is the output `john:` an array of of objects? – Bravo Mar 25 '22 at 04:20
  • I'm accessing a data.txt and converting array of strings to objects – goatstash Mar 25 '22 at 04:22
  • is there more than two lines in the `data.txt`? is it a CSV file with headers? can `person` be present multiple times? have you heard of papaparse (will make this so easy) – Bravo Mar 25 '22 at 04:23
  • @Bravo I have 8 lines of 'John,shoes,200,2' but with different amounts in the same array. The 'person,item,cost,amount' is only mentioned once at the start of the array – goatstash Mar 25 '22 at 04:26
  • Does this answer your question? [Convert Array to Object](https://stackoverflow.com/questions/4215737/convert-array-to-object) – JΛYDΞV Mar 25 '22 at 04:30
  • So you essentially have a CSV file with headers – Bravo Mar 25 '22 at 05:08

2 Answers2

2

If I understand correctly, you may try something like this:

const convert = data => {
  const [columnsText, ...items] = data;
  const columns = columnsText.split(',');
  
  return items.reduce((acc, text) => {
    const { person, ...entries } = Object.fromEntries(text.split(',').map((value, i) => [columns[i], value]));
    entries.totalPriceForItems = String(entries.cost * entries.amount);
    
    if(acc[person]) {
      acc[person].push(entries);
    } else {
      acc[person] = [entries];
    }
    
    return acc;
  }, {});
};

const result = convert([
  'person,item,cost,amount', 
  'John,shoes,200,2', 
  'Bob,glasses,50,3',
  'John,shirts,100,5',
]);

console.log(result);
Hao Wu
  • 17,573
  • 6
  • 28
  • 60
1

According to your comment,

I have 8 lines of 'John,shoes,200,2' but with different amounts in the same array. The 'person,item,cost,amount' is only mentioned once at the start of the array

What I understand is that you have a csv with headers and multiple rows. If that is the case, then your data would resemble something like this:

data = [
  'person,item,cost,amount',
  'John,shoes,200,2',
  'Adam,pants,60,1',
  'Kelly,skirt,180,2',
  'John,skirt,150,3'
]

Then you could consider the following approach, that is generic enough to adapt to different headers, and multiple data rows with repeated keys (person names).

// here, you define a function to transform each row of your data,
// like parsing numeric attributes and calculating the totals
function transform(row) {
  row.cost = Number.parseInt(row.cost)
  row.amount = Number.parseInt(row.amount)
  row.total = row.cost * row.amount
  return row
}

// The following logic is generic, and can be used 
// to map and aggregate any kind of csv with headers
hdrs = data.shift().split(',').slice(1)
rows = data.map(r => r.split(',')).reduce((acc, [n, ...kvs]) => 
  ({ ...acc, [n]: [...acc[n] || [], transform(Object.fromEntries(kvs.map((v, i) => [hdrs[i], v])))] }), {})

Output:

{ 
  John: [
    { item: "shoes", cost: 200, amount: 2, total: 400 }, 
    { item: "skirt", cost: 150, amount: 3, total: 450 }], 
  Adam: [
    { item: "pants", cost:  60, amount: 1, total:  60 }], 
  Kelly: [
    { item: "skirt", cost: 180, amount: 2, total: 360 }]
}
Rodrigo Rodrigues
  • 7,545
  • 1
  • 24
  • 36