I have this array
myarr = [
'=title1',
'longText0...',
'longtText1...',
'=title2',
'longTextA...',
'longtTextB...',
'longtTextC...'
];
symbol =
indicates that is is a property, next to that is a list of items that belongs to that property
I want to transform that array into object
myObj = {
title1: [
'longText0...',
'longtText1...',
],
title2: [
'longTextA...',
'longtTextB...',
'longtTextC...'
]
}
I come up with this code so far:
const arrayToObject = (array) =>
array.reduce((obj, item) => {
if(item.startsWith('=')) {
const itemName = item.replace('=', '')
obj[itemName] = itemName;
} else {
//add the rest....
}
return obj
}, {})
console.log(arrayToObject(myarr))
My challenges so far is that I am not sure how to turn obj[itemName]
so I can assign the items to it. Any ideas how to do that?
CodePudding user response:
I wouldn't do that with reduce
but with a simple for
loop, because you have to carry the itemname
over multiple iterations
let o = {}, n = '';
for (let k of arr) {
if (k.startsWith('=')) {
n = k.substring(1);
o[n] = []
} else {
o[n].push(k);
}
}
You can of course also do it with reduce
, but you have to put the declaration of itemname
outside of the callback
let n = '';
let o = arr.reduce((a, c) => {
if (c.startsWith('=')) {
n = c.substring(1);
a[n] = [];
} else {
a[n].push(c);
}
return a;
}, {});
Please be aware, there is no error handling, ie the code assumes your array is well structured and the first element in the array must start with =
CodePudding user response:
A reduce
based approach which does not depend on outer scope references for keeping track of the currently to be built/aggregated property makes this information part of the reducer function's first parameter, the previousValue
which serves as an accumulator/collector object.
Thus, as for the OP's task, this collector would feature two properties, the currentKey
and the result
, where the former holds the state of the currently processed property name and the latter being the programmatically built result.
// - reducer function which aggregates entries at time,
// either by creating a new property or by pushing a
// value into the currently processed property value.
// - keeps the state of the currently processed property
// by the accumulator`s/collector's `currentKey` property
// whereas the result programmatically gets build as
// the accumulator`s/collector's `result` property.
function aggregateEntry({ currentKey = null, result = {} }, item) {
const key = (item.startsWith('=') && item.slice(1));
if (
(key !== false) &&
(key !== currentKey)
) {
// keep track of the currently processed property name.
currentKey = key;
// create a new entry (key value pair).
result[currentKey] = [];
} else {
// push value into the currently processed property value.
result[currentKey].push(item);
}
return { currentKey, result };
}
console.log([
'=title1',
'longText0...',
'longtText1...',
'=title2',
'longTextA...',
'longtTextB...',
'longtTextC...',
].reduce(aggregateEntry, { result: {} }).result);
.as-console-wrapper { min-height: 100%!important; top: 0; }
CodePudding user response:
The following function will give you the desired results
function arrayToObject(arr)
{
let returnObj={};
for(let i =0; i <arr.length; i )
{
if(arr[i].startsWith('='))
{
let itemName = arr[i].replace('=','');
returnObj[itemName]=[];
for(let j=i 1; j <arr.length;j )
{
if(arr[j].startsWith('='))
{
break;
}
else
{
let value = arr[j];
returnObj[itemName].push(value) ;
}
}
}
}
return returnObj;
}
CodePudding user response:
Here a version with reduce
const myarr = [
'=title1',
'longText0...',
'longtText1...',
'=title2',
'longTextA...',
'longtTextB...',
'longtTextC...'
];
const obj = myarr.reduce((res, el) => {
if(el.startsWith('=')){
const key = el.substring(1)
return {
data: {
...res.data,
[key]: [],
},
key
}
}
return {
...res,
data:{
...res.data,
[res.key]: [...res.data[res.key], el]
}
}
}, {
data: {},
key: ''
}).data
console.log(obj)