0

I have an object and I need to split the values into an array like below

Ex: {firstName1: "Tom", lastName1: "Jerry", firstName2: "Stuart", lastName2: "Little"}

I want the output to be like

[{fName: "Tom", lName: "Jerry"},
{fName: "Stuart", lName: "Little"}]

I can do this like

      let persons= new Array<Person>(); //Assume Person is a Typescript class
      let p1 = new Person(); 
      p1.fName= data.firstName1;
      p1.lName= data.lastName1;
      persons.push(p1);
      let p2= new Person(); 
      p2.fName= data.firstName2;
      p2.lName= data.lastName2;
      persons.push(p2);

I'm looking for an optimized/recommended way of achieving this.

4
  • 1
    What exactly do you mean by optimising it. What you are doing here seems fine. Recommended will be to put new person bit in a loop. Commented Oct 1, 2020 at 11:26
  • Optimizing in the sense like I feel this is not the only option to achieve this if possible to reduce number of lines of code as well. I would have done for loop part but the object many more additional properties which are not related to Person object. Commented Oct 1, 2020 at 11:34
  • I am assuming firstname and lastname remains same for all, the suffix (number) changes!? you still have to traverse through the object, but need to condition it according to the string parameter of the key i,e my assumption Commented Oct 1, 2020 at 11:43
  • the pilchard answer might help Commented Oct 1, 2020 at 11:44

4 Answers 4

2

let requiredObject  = [];
let firstNames = []; 
let lastNames = [];
let inputObject = {firstName1: "Tom", lastName1: "Jerry", firstName2: "Stuart", lastName2: "Little"}
firstNames = Object.keys(inputObject).filter(each => each.includes('firstName'));
lastNames = Object.keys(inputObject).filter(each => each.includes('lastName'));
for(var i = 0; (firstNames.length > i &&  lastNames.length > i); i++) {
  var data = {};
  data.fName = inputObject[firstNames[i]];
  data.lName = inputObject[lastNames[i]]
  requiredObject.push(data);
}

console.log(requiredObject);

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

Comments

1

How about this?

let persons= new Array<Person>();
let person = {}; //Not familiar with typescript much. Not sure if it would be {} or new Person();

Object.keys(data).forEach((key,index)=>{
    if(index%2 == 0) {
        //firstName
        person.fName = data[key];
    } else {
        //lastName
        person.lName = data[key];
        persons.push(person);
        person = {}; // or new Person();
    }
});

2 Comments

Thanks for your input. The object contain many more properties which are not related to Person class. so looping through properties and plucking using Index may not help.
You can use a regex instead of index%2 to determine the required key names
1

Update Reduce time complexity by avoiding nested iterations

const combined = {firstName1: "Tom", lastName1: "Jerry", age1: 101, firstName2: "Stuart", lastName2: "Little", age2: 15, petName2: "dog"};

const personMap = Object.entries(combined).reduce((acc, [k, v]) => {
   const pNum = k.match(/[0-9]+$/)[0];
   const normalKey = k.slice(0, (k.length - pNum.length));
   
   const match = acc.get(pNum),
          attr = {[normalKey]: v};
        match ?
          Object.assign(match, attr) :
          acc.set(pNum, {...attr});
          
   return acc;
}, new Map());

const refactored = [...personMap.values()].map(p => ({...p}));

console.log(refactored);

You can use a .reduce() on the keys of the initial object and generate the lastName key from the firstName to avoid ordering problems.

const combined = {firstName1: "Tom", lastName1: "Jerry", firstName2: "Stuart", lastName2: "Little"};

const refactored = Object.keys(combined).reduce((a, k) => {
    if (k.startsWith('firstName')){
      a.push({fName: combined[k], lName: combined[k.replace('firstName', 'lastName')]});
    }
   return a;
  }, []);
  
  console.log(refactored);

You can generalize this for any number of attributes and pass an array of attributes to map to the new array.

const combined = {firstName1: "Tom", lastName1: "Jerry", age1: 101, firstName2: "Stuart", lastName2: "Little", age2: 15};
const attributes = ['firstName', 'lastName', 'age'];

const refactored = Object.keys(combined).reduce((a, k) => {
    if (k.startsWith('firstName')){
      const p = attributes.reduce((b, attr) => (b[attr] = combined[k.replace('firstName', attr)], b), {});
      a.push({...p});
    }
   return a;
  }, []);
  
  console.log(refactored);

Or for an arbitrary number of attributes .filter the keys of the object by personNumber.

const combined = {firstName1: "Tom", lastName1: "Jerry", age1: 101, firstName2: "Stuart", lastName2: "Little", age2: 15, petName2: "dog"};

const refactored = Object.keys(combined).reduce((a, k) => {
    if (k.startsWith('firstName')){
      const pNum = k.replace('firstName', '');
      const p = Object.keys(combined)
          .filter(k => k.endsWith(pNum))
          .reduce((b, attr) => (b[attr.replace(pNum, '')] = combined[attr], b), {});
      a.push({...p});
    }
   return a;
  }, []);
  
  console.log(refactored);

Comments

0

let obj = {firstName1: "Tom", lastName1: "Jerry", firstName2: "Stuart", lastName2: "Little"}
let keysArr = Object.keys(obj)
let valueArr = Object.values(obj)

let result = []

keysArr.map((x, i) => {
  if(x.indexOf('first') != -1){
    result.push({ fName: valueArr[i], lName: valueArr[i+1] })
  }
})

console.log(result)

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.