I have an array that I need to turn into an object with the given values.
This is the input array
let actions = ['CREATE: id=14&amount=800¤cy=USD','FINALIZE: id=14&amount=800¤cy=USD','PAY: id=14'
]
How would I turn it into this object.
let result ={
'create': 800,
'finalize': 800,
'pay':14
}
so far I have a loop to check if the key in the array is available, but I'm lost on next steps. One of coworkers say Regex might be the best option.
for(let x = 0; x <=actions.length;x++){
if(actions[x].icludes('CREATE')){
} else(actions[x].icludes('FINALIZE')){
} else(actions[x].icludes('PAY')){
}
}
Ant help is appreciated.
4 Answers 4
You could split each string at :\s+ to get a key and the string to be parsed. You'll get 2 values in the resulting array. Use destructuring to get them to separate variables
["CREATE", "id=14&amount=800¤cy=USD"]
Then use URLSearchParams constructor on the second value get a key-value pair from the query string.
Some keys need amount while some keys need id's value. So, you can create a mapper object. This maps the key with the name to be searched inside URLSearchParams.
const mapper = {
PAY: "id",
CREATE: 'amount',
FINALIZE: 'amount',
default: "amount"
};
Here, PAY needs id value. If you have more keys, you could add it here. You could add CREATE: "amount" to this object as well. But, since that is the default, I have skipped that. The default key can be used if a key is not found in mapper. Return an object with the key and the value from the parse function.
Then reduce the array and merge each parsed object to create the output
const actions = ['CREATE: id=14&amount=800¤cy=USD', 'FINALIZE: id=14&amount=800¤cy=USD', 'PAY: id=14']
const mapper = {
PAY: "id",
//CREATE: 'amount', // you could add CREATE and FINALIZE if you want
default: "amount"
};
function parse(str) {
const [key, value] = str.split(/:\s+/);
const param = new URLSearchParams(value).get(mapper[key] || mapper.default);
return { [key.toLowerCase()]: param };
}
const output = actions.reduce((acc, str) => Object.assign(acc, parse(str)), {});
console.log(output)
2 Comments
Considering that your expected output doesn't follow a single structure, i opted for returning all values, instead of an arbitrary one. How ever if you have some business logic to justify selecting different values to return, you could easily change the code to accommodate this.
const actions = [
'CREATE: id=14&amount=800¤cy=USD',
'FINALIZE: id=14&amount=800¤cy=USD',
'PAY: id=14'
];
const actionsData = actions.reduce((res, str) => {
const [op, query] = str.split(': ');
const kvPairs = query.split('&');
const data = kvPairs.reduce((res, kvStr) => {
const [key, value] = kvStr.split('=');
res[key] = value;
return res;
}, {});
res[op] = data;
return res;
}, {});
console.log(actionsData);
Comments
As a regex example, this could also work. Of course, there may be a more robust regex rule always. (and more scalable)
let actions = [
'CREATE: id=14&amount=800¤cy=USD',
'FINALIZE: id=14&amount=800¤cy=USD',
'PAY: id=14'
]
let result = actions.reduce((acc, item) => {
if (item.match(/^CREATE:.+amount=(\d+)/)) {
acc.create = item.match(/^CREATE:.+amount=(\d+)/)[1];
} else if (item.match(/^FINALIZE:.+amount=(\d+)/)) {
acc.finalize = item.match(/^FINALIZE:.+amount=(\d+)/)[1];
} else if (item.match(/^PAY:.+id=(\d+)/)) {
acc.id = item.match(/^PAY:.+id=(\d+)/)[1];
};
return acc;
}, {})
console.log(result);
Comments
Here's a solution:
let actions = ['CREATE: id=14&amount=800¤cy=USD','FINALIZE: id=14&amount=800& currency=USD','PAY: id=14']
let actionObject = [];
for(let i=0;i<actions.length;i++){
// Split where it has colon and space
let splitter = actions[i].split(": ");
// Get label (and make it lowercase)
let theLabel = splitter[0].toLowerCase();
// remove label from array
splitter.splice(0,1);
// rejoin array if any values contained colon and space
splitter = splitter.join(": ");
// find amount= and split that
splitter2 = splitter.split("amount=");
// splitter2[1] will be everything after "amount="
// if amount= didn't exist it will be undefined
if(splitter2[1] !== undefined){
// Now we just split the other side of the amount where &
// if amount is the last thing and there's no &, it won't matter
splitter2 = splitter2[1].split("&");
// Now create the key (l1) and value (splitter2[0])
actionObject[l1] = splitter2[0];
}else{
// If amount is not found, we get id instead, same process
splitter2 = splitter.split("id=");
if(splitter2[1] !== undefined){
splitter2 = splitter2[1].split("&");
actionObject[l1] = splitter2[0];
}
}
}
So, now you have an object, actionObject and it contains the amounts, but only for the values that contained amount or id.
actionObject {
create: "800",
finalize: "800",
pay: "14"
}