I want to create objects with properties in an array by string. I'm extracting "name" from string and "data" without round brackets and trying to create objects in the array with the property "name" and property "data". But actual result differs from expected, please help to solve
const names = ["name1 /2 (data1)", "name1 /2 (data2)", "name2 /1 (data1)"]
const flag = true
names.forEach(name => {
console.log(getStructuredDataFromNames(name))
})
function getStructuredDataFromNames(name) {
const names = {}
// extract name from string and conver to valid format - 'name1'
const formattedName = name.substr(0, name.indexOf("/")).replace(/\s+/g, "")
// extract data from string and conver to valid format - 'data1'
const formattedData = name.match(/\((.*)\)/).pop()
const reference = {
formattedData,
flag
}
// if no name then create a new property by this name
if (!names[name]) {
names[name] = [{
data: [reference]
}]
} else {
// if object have name but name have more then 1 data then push this data to array
names[name].push(reference)
}
const result = Object.keys(names)
return result.map(el => ({
name: el,
data: names[el]
}))
}
Expected result
[{
name: "name1",
data: [{
flag: true,
formattedData: "data1"
},
{
flag: true,
formattedData: "data2"
}
]
},
{
name: "name2",
data: [{
flag: true,
formattedData: "data1"
}]
}
]
-
From experience it is better on the long run to correct the data source, instead of trying some weird parsing If possible of course.JavaScript– JavaScript2020年12月24日 08:16:39 +00:00Commented Dec 24, 2020 at 8:16
2 Answers 2
Although the code is not that clean, it can do the job. My flow is first to remove the spaces, and then split the name and the data, remove the number before the data and remove (). If "formattedNames" already have the same "name" object, push the data to the "name" object.
const names = ["name1 /2 (data1)", "name1 /2 (data2)", "name2 /1 (data1)"]
const formattedNames = []
names.forEach(value =>{
const processedName = value.replace(/ /g,'').split("/")
const formattedName = formattedNames.find((object)=>{ return object.name === processedName[0]})
const formattedData = processedName[1].split("(")[1].replace(")","")
if (!formattedName) {
formattedNames.push({name: processedName[0],data: [{flag: true, formattedData}]})
} else {
formattedName.data.push({flag: true, formattedData})
}
})
console.log(formattedNames)
Comments
Here is a really inefficient way to do it
var names2 = ["name1 /2 (data1)", "name1 /2 (data2)", "name2 /1 (data1)"]
var flag2 = true
var result2 = names2.map(x =>
{
return {
name: x.split(" ")[0],
data:
[
{
flag: flag2,
formattedData: x.match(/\((.*)\)/).pop()
}
]
}
})
result2.forEach((el, index, arr) =>
{
let el2 = arr.filter(x => x.name == el.name)[0];
if(el2 == el)
return;
el2.data = el2.data.concat(el.data);
delete arr[index];
})
result2 = result2.filter(x => true);
console.log(result2);