-4

I need to convert this object

{
  person1_name: "John",
  person0_name: "Rob",
  person1_age: 36,
  person0_age: 45,
  total: 2,
}

into this format

{
    mambers: [
      {
        name: "Rob",
        age: 45,
      },
      {
        name: "John",
        age: 36,
      },
    ],
    total: 2,
  }

Does anyone know how to do it in not to complicated way using JavaScript?

dariusz
  • 441
  • 1
  • 5
  • 17
  • 6
    Interesting one, have you tried anything yet? – sp00m Sep 02 '20 at 10:25
  • please provide more info, like if the relevant keys always starts with `personN_name` where `N` in integer, if there are always coupled keys `personN_name`-``personN_age` etc. – Jan Stránský Sep 02 '20 at 10:32
  • 2
    Familiarize yourself with [how to access and process nested objects, arrays or JSON](https://stackoverflow.com/q/11922383/4642212) and use the available [`Object`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object#Methods_of_the_Object_constructor), [`Array`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array#Methods) and [`String`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String#Instance_methods) methods. – Sebastian Simon Sep 02 '20 at 10:38
  • 1
    you allways have person0, person1, person2, .. up to total-1? – Sascha Sep 02 '20 at 10:44
  • Related: [Iterating through a badly designed API](https://stackoverflow.com/q/49835981/4642212). – Sebastian Simon Sep 02 '20 at 10:48

4 Answers4

0

Following is one of the way.

const x={
  person1_name: 'John',
  person0_name: 'Rob',
  person1_age: 36,
  person0_age: 45,
  total: 2
}

const extractKey = keyName => obj =>  Object.keys(obj).filter(key => key.includes(keyName))

const names = extractKey('_name')(x);
 
const ages = extractKey('_age')(x);

const transform = (names, ages) => obj => ({ members: names.map((key, index) => ({name:obj[key], age: obj[ages[index]]})), total:names.length})

console.log(transform(names, ages)(x))
0

Asuming that there exists for every 0, 1, ... total-1 an entry for name and age you can use this:

let data = {
  person1_name: "John",
  person0_name: "Rob",
  person1_age: 36,
  person0_age: 45,
  total: 2,
};

let result = {members: [], total: data.total};

for (let i=0; i<data.total; i++) {
    result.members.push({
        name: data['person' + i + '_name'],
        age: data['person' + i + '_age'],
    });
}

console.log(result);
Sascha
  • 4,576
  • 3
  • 13
  • 34
0

Assuming all the keys are in the format of 'person{index}_{name}', i.e. 'person0_name', a regex approach can be taken, as such:

var input = {
    person1_name: "John",
    person0_name: "Rob",
    person1_age: 36,
    person0_age: 45,
    total: 2,
};

function transform(input) {
    var output = {};
    var members = {};
    var keys = Object.keys(input);

    for (var i = 0; i < keys.length; i++) {
        var key = keys[i];
        var match = key.match(/person(.*[^_])_(.*)/);
        if (!match) {
            output[key] = input[key];
            continue;
        }

        var member = members[match[1]] || {};
        member[match[2]] = input[key];
        members[match[1]] = member;
    }

    output.members = Object.keys(members).map((k) => members[k]);
    return output;
}

console.log(transform(input));

This function can accommodate more than just 'name' and 'age', so if additional properties need transforming this will work.

Reece Russell
  • 347
  • 1
  • 11
0

A solution not requiring contiguous numbering:

var input = {
    person1_name: "John",
    person0_name: "Rob",
    person1_age: 36,
    person0_age: 45,
    total: 2,
}

// match N from personN_name, using lookbehind and lookahead to match only the number
// use "optional chaining index" ?.[0] to extract the first match is found
const match = key => key.match(/(?<=^person)\d+(?=_name$)/)?.[0]

// "functional" approach
// extract keys from input, map them with the matching regexp and filter actual matches
var ids = Object.keys(input).map(k => match(k)).filter(Boolean)
// map ids to {name,age} objects
var members = ids.map(id => ({name:input[`person${id}_name`],age:input[`person${id}_age`]}))
// construct output
var output = {total:input.total,members}
console.log(output)

// "iterative" pproach
// initial value of outpit
var output = {total:input.total,members:[]}
for (var [k,v] of Object.entries(input)) { //for each key-value from input
    var id = match(k) // try to get key
    if (!id) continue // if id not found, continue to next kev-value pair
    var name = v // the match is against personN_name, so v is the name
    var age = input[`person${id}_age`] // get age
    output.members.push({name,age}) // push new member
}
console.log(output)
Jan Stránský
  • 1,671
  • 1
  • 11
  • 15