Reputation: 323
I have a JSON object array that looks something like this
[
{"PM":"Jane","e":"[email protected]","h":"15.00","w":"10/30/2016 12:00:00 AM","c":"John","p":"Happy Town USA"},
{"PM":"Jane","e":"[email protected]","h":"11.00","w":"11/06/2016 12:00:00 AM","c":"John","p":"Happy Town USA"},
{"PM":"Jill","e":"[email protected]","h":"21.00","w":"10/30/2016 12:00:00 AM","c":"John","p":"Sad Town USA"},
{"PM":"Jill","e":"[email protected]","h":"12.00","w":"11/06/2016 12:00:00 AM","c":"John","p":"Sad Town USA"}
]
Looking at the data all "columns" for a given PM,e, p, c combination the data is same except the w and the h fields. I need to transform this data into a new object that would look something like this.
[
{PM:"Jane",e:"[email protected]",c:"John",p:"Happy Town USA",
Details:[{"w":"10/30/2016","h":"15.00"},{"w":"11/06/2016","h":"11.00"}]},
{PM:"Jill",e:"[email protected]",c:"John",p:"Sad Town USA",
Details:[{"w":"10/30/2016","h":"21.00"},{"w":"11/06/2016","h":"12.00"}]}
]
It's kind of like making columns from rows in a SQL query, unfortunately I have little control over the source data so that is not an option.
Upvotes: 0
Views: 103
Reputation: 54
Java approach only: This question sounds very challenging for a quick solution. I got a partial solution here using Java Oson library I created, here is the source file:
@Test
public void testTableMerge2() {
List<Map> list = oson.readValue("rows2Columns.txt");
Map<String, List> collected = new HashMap<>();
for (Map map: list) {
String key = (String) map.get("PM");
List obj = collected.get(key);
if (obj == null) {
obj = new ArrayList();
collected.put(key, obj);
}
obj.add(map);
}
Config config = merge.getConfig();
config.numericValue = NUMERIC_VALUE.MERGE_UNIQUE;
config.nonnumericalValue = NONNUMERICAL_VALUE.MERGE_UNIQUE;
config.listValue = LIST_VALUE.MERGE_UNIQUE;
Map<String, Object> results = new HashMap<>();
for (String key: collected.keySet()) {
results.put(key, merge.merge(collected.get(key)));
}
Collection result = results.values();
// oson.pretty();
String json = oson.serialize(result);
String expected = "[{\"PM\":\"Jill\",\"e\":\"[email protected]\",\"h\":[\"21.00\",\"12.00\"],\"w\":[\"10/30/2016 12:00:00 AM\",\"11/06/2016 12:00:00 AM\"],\"c\":\"John\",\"p\":\"Sad Town USA\"},{\"PM\":\"Jane\",\"e\":\"[email protected]\",\"h\":[\"15.00\",\"11.00\"],\"w\":[\"10/30/2016 12:00:00 AM\",\"11/06/2016 12:00:00 AM\"],\"c\":\"John\",\"p\":\"Happy Town USA\"}]";
assertEquals(expected, json);
}
Upvotes: 0
Reputation: 45155
var source = [{
"PM": "Jane",
"e": "[email protected]",
"h": "15.00",
"w": "10/30/2016 12:00:00 AM",
"c": "John",
"p": "Happy Town USA"
}, {
"PM": "Jane",
"e": "[email protected]",
"h": "11.00",
"w": "11/06/2016 12:00:00 AM",
"c": "John",
"p": "Happy Town USA"
}, {
"PM": "Jill",
"e": "[email protected]",
"h": "21.00",
"w": "10/30/2016 12:00:00 AM",
"c": "John",
"p": "Sad Town USA"
}, {
"PM": "Jill",
"e": "[email protected]",
"h": "12.00",
"w": "11/06/2016 12:00:00 AM",
"c": "John",
"p": "Sad Town USA"
}];
// First we'll transform the source into a dictionary
var dict = source.reduce(function(p, c) {
// We'll use the combination of PM,e,c and p to build a key
var key = [c.PM, c.e, c.c, c.p].join("-");
if (p[key]) {
// If we've seen this key before, we'll just add to the Details
p[key].Details.push({
w: c.w,
h: c.h
});
} else {
// otherwise we create a new entry and populate it
p[key] = {
PM: c.PM,
c: c.c,
e: c.e,
p: c.p,
Details: [{
w: c.w,
h: c.h
}]
}
}
return p;
}, {});
// We now have a dictionary
console.log(dict);
// If you really need an array (and don't care about order), we can transform
// the dictonary to an array (order is not guaranteed here)
var result = Object.keys(dict).map(function(a) {
return dict[a];
});
console.log(result);
Upvotes: 1
Reputation: 21965
You want to use reduce
to accomplish these kinds of transformations in JavaScript:
var arr = /* your array of objects goes here */;
var results = Object.values(arr.reduce(function(obj, row) {
var pm = row.PM;
// here we check to see if we already have an aggregator for that pm
if (!obj[pm]) {
obj[pm] = {
PM: pm,
e: row.e,
c: row.c,
p: row.p
Details: []
};
}
// now we need to add a record to the Details
obj[pm].Details.push({ w: row.w, h: row.h });
// common mistake using reduce is to forget
// to return the accumulator
return obj;
}, {}));
You can convert back to a JSON string with JSON.stringify
. Note that Object.values
is not yet implemented in every JavaScript environment, you may need to polyfill it.
Upvotes: 2