0

I have this value:

const sample = [{

  name: "name",
  value1: 1,
  mean: 2,
  create: 10,

  age: "age",
  player1: 20,
  player2: 40,

  sample: "sample",
  player3: 30,
  player4: 100,
}];

to be mapped into:

{
  name: {
    value: 1,
    mean: 2,
    create: 10
  },
  age: {
    player1: 20,
    player2: 40
  },
  sample: {
    player3: 30,
    player4: 100
  }
}

I know what I can do is to map it manually but my list is around 50 so it's not possible.

Edit:

The key property will be if it's string and the number will be the values in that order

6
  • do you know the properties beforehand which belong to name and which to age, currently its a hardcoded list Commented Aug 19, 2020 at 12:43
  • The key property will be if it's string and the number will be the values Commented Aug 19, 2020 at 12:45
  • No I mean player1 and player2 are fixed to age right, do you know what will be mapped to it Commented Aug 19, 2020 at 12:46
  • 1
    @ajbee ... but you are aware that you are actually relying then on a structure that always has to ensure that with e.g. Object.keys will present the keys exactly in the order of their creation/assignment. And the environment that creates such objects has to ensure exactly such a viable and reproducible order as well. Commented Aug 19, 2020 at 12:52
  • 1
    I just saw your edit, and actually, you cannot have two properties in a single object that have the same key, so in your example, you cannot have multiple of player1 and player2 with different values - the second value of player1 will replace the first one. Commented Aug 19, 2020 at 13:03

7 Answers 7

2

Your description is not clear, however, I think you want to remap a group of properties into a new property, only if key and value is the same.

Moreover, I put a new key = value = "other" and the properties afterwards are grouped under "other", so you don't have to specify all of the keys...

const sample = [{
  name: "name",
  value1: 1,
  mean: 2,
  create: 10,

  age: "age",
  player1: 20,
  player2: 40,
}, {
  name: "name",
  value1: 1,
  mean: 2,
  create: 10,

  age: "age",
  player1: 20,
  player2: 40,

  other: "other",
  p2: "ldkdskd",
  p1: 10
}];
    
function remapdata(data) {
  const obj = {};
  const keys = Object.keys(data);
  let lastGroup = undefined;
  let i = 0;`enter code here`
  while(i < keys.length) {
    if(keys[i] === data[keys[i]]) {
      obj[keys[i]]= {};
      lastGroup=keys[i];  
    } else if (lastGroup) {
      obj[lastGroup][keys[i]] = data[keys[i]];
    }
    i++;
  } 
  return obj;
}
const mapped = sample.map(remapdata);

console.log(mapped);
.as-console-wrapper { min-height: 100%!important; top: 0; }

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

Comments

1

Everyone should be aware of that any approach which is going to restructure any object's key-value pair(s) is actually relying on a structure that always has to ensure, for e.g. Object.keys, a key order that exactly represents the order of any key's creation. Also the environment that creates such objects has to ensure exactly such a viable and reproducible order as well.

If one could generalize that, " ... whenever in a key-value pair key equals value, one wants to create a new object assigned to the resampled structure via key.", one should go with the beneath provided approach as is. Otherwise one has to limit the condition that is responsible for creating new sub-structures to any string type value which then also does limit the types the original structure is allowed to feature. ...

const sampleList = [{
  name: "name",
  value1: 1,
  mean: 2,
  create: 10,

  age: "age",
  player1: 20,
  player2: 40,

  sample: "sample",
  player3: 30,
  player4: 100
}, {
  sample: "sample",
  player1: 130,
  player2: 1100,

  name: "name",
  value1: 11,
  mean: 12,
  create: 110,

  age: "age",
  player3: 120,
  player4: 140
}];


function restructureSample(sample) {
  const newSample = {};
  return Object.entries(sample).reduce((reference, tuple, idx, arr) => {

    const [key, value] = tuple;
  //if (typeof value === 'string') {  // - more generic, but limiting the use cases.
    if (key === value) {              // - maybe even more precise.

      reference = newSample[key] = {};
    } else {
      reference[key] = value;
    }
    return (((idx === (arr.length - 1)) && newSample) || reference);

  }, newSample);
}


console.log(sampleList.map(restructureSample));
.as-console-wrapper { min-height: 100%!important; top: 0; }

Comments

1

Use Array#map for mapping it to the new object-structure inside.

const sample = [
 {
  name: "name",
  value1: 1,
  mean: 2,
  create: 10,
  age: "age",
  player1: 20,
  player2: 40,
 }
];

let result = sample.map(elem => ({
    any : {
        name: {
           value: elem.value1,
           mean: elem.mean,
           create: elem.create
        },
        age: {
           player1: elem.player1,
           player2: elem.player2
        }
   }
}))

console.log(result);

Comments

1

To do this the right way, you need to specify properties that will fall under name and age in the final object, something like in the following example:

const sample = [
  {
    name: "name",
    value1: 1,
    mean: 2,
    create: 10,
    age: "age",
    player1: 20,
    player2: 40
  },
  {
    name: "fred",
    value1: 3,
    mean: 5,
    create: 101,
    age: "age",
    player1: 202,
    player2: 401
  }
];


const keyValuesMap = {
  // `name` property will have `value1`, `mean`, and `create` properties
  name: ["value1", "mean", "create"],
  
  // `age` property will have `player1` and `player2` properties
  age: ["player1", "player2"]
};

const result = sample.map((item) => {
  // map over the `sample` data and get the key/value pairs of each
  // item, then use `reduce` to create a new object based on the
  // `keyValuesMap` specified above
  return Object.entries(item).reduce((accumulator, [key, value]) => {
    const name = accumulator.name || {};
    const age = accumulator.age || {};

    // if value belongs to the `name` property, add to it
    if (keyValuesMap.name.includes(key)) {
      name[key] = value;
    }
    // if value belongs to the `age` property, add to it
    if (keyValuesMap.age.includes(key)) {
      age[key] = value;
    }

    accumulator.name = name;
    accumulator.age = age;

    return accumulator;
  }, {});
});

console.log("result", result);

References:

Comments

1

You probably want something like this

const sample = [ { name: "name", value1: 1, mean: 2, create: 10, age: "age", player1: 20, player2: 40, }, ];

res = sample.reduce((r, c) => {
  let key;
  Object.entries(c).forEach((o) => {
(k = o[0]), (v = o[1]);
typeof v == "string" ? ((key = v), (r[v] = {})) : (r[key][k] = v);
  });
  return r;
}, {});
console.log(res);

Comments

0

Use Array.prototype.reduce to reduce the array and remap the existing properties into your desired format.

const sample = [
 {
  name: "name",
  value1: 1,
  mean: 2,
  create: 10,
  age: "age",
  player1: 20,
  player2: 40,
 }
];

const result = sample.reduce((acc, { value1, mean, create, player1, player2 }) => {
    acc.push({
        name: {
            value1,
            mean,
            create
        },
        age: {
            player1,
            player2
        }
    });
    return acc;
}, []);

console.log(result);

For dynamic keys you can do something like -

const sample = [
 {
  name: "name",
  value1: 1,
  mean: 2,
  create: 10,
  age: "age",
  player1: 20,
  player2: 40,
 }
];

const keyMapping = {
    name: ['value1', 'mean', 'create'],
    age: ['player1', 'player2']
};

const result = sample.reduce((acc, curr) => {
    const obj = Object.entries(keyMapping).reduce((accumulator, [key, val]) => {
        accumulator[key] = val.reduce((r, c) => {
            r[c] = curr[c];
            return r;
        }, Object.create(null));
        return accumulator;
    }, Object.create(null));
    
    acc.push(obj);
    return acc;
}, []);

console.log(result);

1 Comment

@ajbee ... then you need to be more specific. Like e.g if the sample structure is not as fixed as shown in the Q, how else could it look like, what would be the expected result in those cases.
0

You can use .map function to iterate over the objects, and keep track of the last key to add integer-properties to them:

const sample = [
 {
  name: "name",
  value1: 1,
  mean: 2,
  create: 10,
  age: "age",
  player1: 20,
  player2: 40,
  sample: "sample",
  player1a: 30,
  player2a: 100,
 },
 {
  name: "name",
  value1: 11,
  mean: 22,
  create: 130,
  age: "age",
  player1: 210,
  player2: 430,
  sample: "sample",
  player1a: 340,
  player2a: 1100,
 },
 {
  name: "name",
  value: 313,
  mean: 421,
  create: 23,
  age: "age",
  player1a: 440,
  player2a: 40,
 }
];
let lastKey = null;
let mapped = sample.map(elem => {
     let obj = { any: {} };
     let any = obj.any;
     for(var p in elem){
          let key = p, value = elem[p];
          if(typeof(value)=="string"){
               any[key] = {};
               lastKey = key;
          }else if(typeof(value)=="number"){
               if(lastKey)
                    any[lastKey][key] = value;
               else
                    any[key] = value;
          }
     }
     return obj;
});
console.log(mapped);

Note that you cannot have two same keys (player1 and player2) since it should be unique.

2 Comments

Why are ppl down voting this?
This results in another array

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.