0

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&currency=USD','FINALIZE: id=14&amount=800&currency=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

2

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&currency=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&currency=USD', 'FINALIZE: id=14&amount=800&currency=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)

Sign up to request clarification or add additional context in comments.

2 Comments

gorgeous approach
I actually like like this approach, thank you and it your explanation was very straightforward.
0

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&currency=USD',
  'FINALIZE: id=14&amount=800&currency=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

0

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&currency=USD',
  'FINALIZE: id=14&amount=800&currency=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

0

Here's a solution:

let actions = ['CREATE: id=14&amount=800&currency=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"
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.