4

Let's say, I have an Array of object which looks like:

  var jsonData = [
  {"DS01":123,"DS02":88888,"DS03":1,"DS04":2,"DS05":3,"DS06":666},
  {"DS01":123,"DS02":88888,"DS03":2,"DS04":3,"DS05":4,"DS06":666},

  {"DS01":124,"DS02":99999,"DS03":3,"DS04":4,"DS05":5,"DS06":333},
  {"DS01":124,"DS02":99999,"DS03":5,"DS04":6,"DS05":7,"DS06":333}
];

You can see there are some common key fields which are DS01, DS02 and DS06. Firstly, I want to find which are common group of keys.

  • For first 2 Objects : DS01 = 123, DS02 = 88888, DS06 = 666
  • For last 2 Objects : DS01 = 124, DS02 = 99999, DS06 = 333

I want to convert this array of objects to a format like this:

    var jsonDataReduced = 
     [{
            "DS01": 123,
            "DS02": 88888,
            "DS03": [1, 2],
            "DS04": [2, 3],
            "DS05": [3, 4],
            "DS06": 666
        },
    
        {
            "DS01": 124,
            "DS02": 99999,
            "DS03": [3, 5],
            "DS04": [4, 6],
            "DS05": [5, 7],
            "DS06": 333
        }
    ];

Let's say, I have another array of objects.

var jsonData2 = [{
    "Mass": 3,
    "Force": 3.1,
    "Acceleration": 4
}, {
    "Mass": 3,
    "Force": 4.1,
    "Acceleration": 4
}];

So after reducing it should be:

var jsonData2 = [{
    "Mass": 3,
    "Force": [3.1, 4.1],
    "Acceleration": 4
}];

I have been trying to do these by using Array.reduce() but not getting an idea on how to do this job efficiently.

Is it possible to

  • making a single function
  • passing these kinds of array of objects as a parameter
  • and finally getting the reduced dataset

What I have tried :

var jsonData2 = [{
        "Mass": 3,
        "Force": 3.1,
        "Acceleration": 4
    }, {
        "Mass": 3,
        "Force": 4.1,
        "Acceleration": 4
    }];

const reduced = jsonData2.reduce((r, e, i, a) => {
  if (i % 2 == 0) {
    const next = a[i + 1];
    const obj = { ...e, Force: [e.Force] }
    if (next) obj.Force.push(next.Force);
    r.push(obj)
  }
  return r;
}, []);

console.log(reduced);
Mike 'Pomax' Kamermans
  • 49,297
  • 16
  • 112
  • 153
Shunjid Rahman
  • 409
  • 5
  • 17
  • 1
    You can use reduce for this, but if you don't show the code you wrote so far, we can't make recommendations that let you change it so it does what you want. And on a predictable data type note, having properties be "either a number or an array" means writing more code later on than if you simple _ensure_ it's always an array, with one or more values, and then checking `.length` later in in your code. – Mike 'Pomax' Kamermans Nov 29 '19 at 17:49
  • 1
    That's not [JSON](http://json.org). These are all array of objects. [What is the difference between JSON and Object Literal Notation?](https://stackoverflow.com/questions/2904131/what-is-the-difference-between-json-and-object-literal-notation) – Andreas Nov 29 '19 at 17:51
  • 1
    do you have always the same count of common keys – Nina Scholz Nov 29 '19 at 17:52
  • 1
    @NinaScholz Yes, the group of common keys are same in count. Because these are being formatted from a table with rowspan. Common values are from merged rows. – Shunjid Rahman Nov 29 '19 at 17:55
  • 1
    @Mike'Pomax'Kamermans What I have done so far was totally a mess. That's why I have not added the snippet you are looking for. But one thing I want to discuss is that I have some solutions where key names are defined in the code. But as you can see I have different other data-sets of pretty same structure, That is what making me confused. – Shunjid Rahman Nov 29 '19 at 18:02
  • The data I'm seeing is super easy to `.reduce` by starting with an empty object, and iterating over each element's properties at each reduction step. So I'd say at the very least show the simplest code you _thought_ was going to work, and then didn't, and then we can show you where you either went wrong, or forgot to do something. – Mike 'Pomax' Kamermans Nov 29 '19 at 18:25
  • @Mike'Pomax'Kamermans I have added the snipped at the last of the question's description. You can see, I have to defined common key names and also the i%2 is not something cool that I am looking for. – Shunjid Rahman Nov 29 '19 at 18:36

1 Answers1

2

You could get common keys and group by them.

var data = [{ DS01: 123, DS02: 88888, DS03: 1, DS04: 2, DS05: 3, DS06: 666 }, { DS01: 123, DS02: 88888, DS03: 2, DS04: 3, DS05: 4, DS06: 666 }, { DS01: 124, DS02: 99999, DS03: 3, DS04: 4, DS05: 5, DS06: 333 }, { DS01: 124, DS02: 99999, DS03: 5, DS04: 6, DS05: 7, DS06: 333 }],
    common,
    temp = data.reduce((r, o, i) => {
        Object.entries(o).forEach(([k, v]) => {
            r[k] = r[k] || [];
            r[k][i] = v;
        });
        return r;
    }, {}),
    min = Infinity,
    result;


Object.entries(temp).forEach(([k, a]) => {
    var s = new Set;
    temp[k] = a.map(v => s.add(v).size);
    min = Math.min(min, s.size);
});

common = Object.keys(temp).filter(k => temp[k][temp[k].length - 1] === min);


result = data.reduce((r, o) => {
    var temp = r.find(q => common.every(k => q[k] === o[k]));
    if (!temp) {
        r.push({ ...o });
    } else {
        Object.keys(o).filter(k => !common.includes(k)).forEach(k => Array.isArray(temp[k]) ? temp[k].push(o[k]) : (temp[k] = [temp[k], o[k]]));
    }
    return r;
}, []);
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
Nina Scholz
  • 376,160
  • 25
  • 347
  • 392