-1

I get a JSON from an external source which has an unknown number of keys. So for example the structure looks like:

data = [{
id: 1,
testObject_1_color: "red",
testObject_1_shape: "triangle",
testObject_2_color: "blue",
testObject_2_shape: "line",
},{
id: 2,
testObject_1_color: "green"
testObject_1_shape: "triangle",
},{
id: 3,
testObject_1_color: "brown",
testObject_1_shape: "square",
testObject_2_color: "black",
testObject_2_shape: "circle",
testObject_3_color: "orange"
testObject_3_shape: "square",
}]

To work with this data I'd need to convert it to something more useful like:

data = [
{object:1, color:"red", shape:"triangle"},
{object:2, color:"blue", shape:"line"},
{object:3, color:"green", shape:"triangle"}
]

The Number of testObject_x_color / shapeis undefined and can theoretically be anything between 0 and 100. Has anybody an idea how to walk through that collection without asking a 100 times if data.hasOwnProperty('testObject_x_color')...?

Torf
  • 1,154
  • 11
  • 29
  • The trick is to loop through the object keys and use if `data.hasOwnProperty(prop)` _dynamically_ – Djave Jun 13 '18 at 07:54
  • Why object 3 shape is triangle on your expected output? – Eddie Jun 13 '18 at 07:57
  • `Object.values( Object.values(input).reduce((objsById, { id, ...rest }) => { if (!objsById[id]) objsById[id] = { id };` then iterate over ...rest and assign to properties of objsById[id] – CertainPerformance Jun 13 '18 at 07:59

2 Answers2

1

use reg and es5 array function.

let data = [{
    id: 1,
    testObject_1_color: 'red',
    testObject_1_shape: 'triangle',
    testObject_2_color: 'blue',
    testObject_2_shape: 'line'
  },
  {
    id: 2,
    testObject_1_color: 'green',
    testObject_1_shape: 'triangle'
  },
  {
    id: 3,
    testObject_1_color: 'brown',
    testObject_1_shape: 'square',
    testObject_2_color: 'black',
    testObject_2_shape: 'circle',
    testObject_3_color: 'orange',
    testObject_3_shape: 'square'
  }
]
let regId = /testObject_(\d{1,3})_(color|shape)/
let res = data
  .reduce((re, obj) => {
    Reflect.ownKeys(obj)
      .filter(key => key !== 'id')
      .forEach(key => {
        let id = obj.id + '' + key.match(regId)[1]
        let isFind = re.find(o => o.id === id)
        if (!isFind) {
          re.push({
            id: obj.id + '' + key.match(regId)[1],
            color: obj[key]
          })
        } else {
          isFind.shape = obj[key]
        }
      })
    return re
  }, [])
  .map(({
    id,
    color,
    shape
  }, index) => ({
    id: index + 1,
    color,
    shape
  }))
console.log(res)
xianshenglu
  • 4,943
  • 3
  • 17
  • 34
1

Another solution with a few loops:

var data = [{
  id: 1,
  testObject_1_color: "red",
  testObject_1_shape: "triangle",
  testObject_2_color: "blue",
  testObject_2_shape: "line"
}, {
  id: 2,
  testObject_1_color: "green",
  testObject_1_shape: "triangle"
}, {
  id: 3,
  testObject_1_color: "brown",
  testObject_1_shape: "square",
  testObject_2_color: "black",
  testObject_2_shape: "circle",
  testObject_3_color: "orange",
  testObject_3_shape: "square"
}];

var sorted = data.reduce(function(result, item) {
  
  // Temp object to store all properties 
  var tmp = {};
  
  // Get all keys of the object
  Object.keys(item).forEach(function(k) {
  
    // Split by underscore
    var parts = k.split('_');
    
    // Process only properties with similar to testObject_1_color names
    // and skip other e.g. id
    if (parts.length === 3) {
      if (!tmp[parts[1]]) {
        tmp[parts[1]] = {};
      }
      tmp[parts[1]][parts[2]] = item[k];
    }
  });
  
  // Fill data in the result array
  Object.values(tmp).forEach(function (pair, i) {
    result.push(pair);
  });
  
  return result;
}, []);

for (var i = 0; i < sorted.length; i++) {
  console.log('object ' + (i + 1) + ': ', sorted[i]);
}
codtex
  • 6,128
  • 2
  • 17
  • 34