I've got a JSON response that looks like this:
{
"COLUMNS":["SETTING_NAME","SETTING_VALUE","COLOR"],
"DATA": [
["setting_1",100.0,"yellow"],
["setting_2",150.0,"red"],
["setting_3",30.0,"green"],
["setting_4",11.0,"blue"]
]
}
How do I find the 'color' for the setting 'setting_4'? Acceptable solutions would either be am easy way to access the data, or a function to transform this into an exploded key/value array like
[
setting_1_value: '100',
setting_1_color: 'yellow',
setting_2_value: "150"
...
]
I've got a JSON response that looks like this:
{
"COLUMNS":["SETTING_NAME","SETTING_VALUE","COLOR"],
"DATA": [
["setting_1",100.0,"yellow"],
["setting_2",150.0,"red"],
["setting_3",30.0,"green"],
["setting_4",11.0,"blue"]
]
}
How do I find the 'color' for the setting 'setting_4'? Acceptable solutions would either be am easy way to access the data, or a function to transform this into an exploded key/value array like
[
setting_1_value: '100',
setting_1_color: 'yellow',
setting_2_value: "150"
...
]
Share
Improve this question
edited Aug 29, 2011 at 22:41
Andrew Shepherd
45.3k33 gold badges145 silver badges211 bronze badges
asked Aug 29, 2011 at 22:35
Luke The ObscureLuke The Obscure
1,5243 gold badges20 silver badges36 bronze badges
2
-
Do you want the value for
setting_4
because you're arbitrarily picking that one, or because it's the last one/highest setting number? – Tom Commented Aug 29, 2011 at 22:40 - Totally arbitrary. The actual data set is much larger. – Luke The Obscure Commented Aug 29, 2011 at 22:46
5 Answers
Reset to default 3You can use this code to put the data into the type of data structure that you asked for:
var response = {"COLUMNS":["SETTING_NAME","SETTING_VALUE","COLOR"],
"DATA":[["setting_1",100.0,"yellow"],["setting_2",150.0,"red"],
["setting_3",30.0,"green"],["setting_4",11.0,"blue"]]};
var data = response.DATA;
var columns = response.COLUMNS;
var hash = {}, item, name, i;
var cols = {};
// remember order of columns
for (i = 0; i < columns.length; i++) {
cols[columns[i]] = i;
}
// fetch data from correct column
for (i = 0; i < data.length; i++) {
item = data[i];
name = item[cols["SETTING_NAME"]];
hash[name + "_value"] = item[cols["SETTING_VALUE"]];
hash[name + "_color"] = item[cols["COLOR"]];
}
hash.num = data.length;
As you requested, this gives you a data structure like this so you can directly read any value you want:
{
"setting_1_value":100,
"setting_1_color":"yellow",
"setting_2_value":150,
"setting_2_color":"red",
"setting_3_value":30,
"setting_3_color":"green",
"setting_4_value":11,
"setting_4_color":"blue",
"num":4
}
jsFiddle here: http://jsfiddle/jfriend00/HZmYN/ that generated this result.
Personally, I would rather use this code to parse it into this type of data structure:
var response = {"COLUMNS":["SETTING_NAME","SETTING_VALUE","COLOR"],
"DATA":[["setting_1",100.0,"yellow"],["setting_2",150.0,"red"],
["setting_3",30.0,"green"],["setting_4",11.0,"blue"]]};
var data = response.DATA;
var columns = response.COLUMNS;
var newData = [], item, obj, i, num, match;
var cols = {};
// remember order of columns
for (i = 0; i < columns.length; i++) {
cols[columns[i]] = i;
}
for (i = 0; i < data.length; i++) {
item = data[i];
obj = {};
obj.value = item[cols["SETTING_VALUE"]];
obj.color = item[cols["COLOR"]];
obj.name = item[cols["SETTING_NAME"]];
match = obj.name.match(/\d+$/);
if (match && match.length > 0) {
obj.settingNumber = parseInt(match[0], 10);
}
newData.push(obj);
}
// now sort the array by the number in the name setting
newData.sort(function(a, b) {
return(a.settingNumber- b.settingNumber);
});
And generates this data structure:
[
{"value":100,"color":"yellow","name":"setting_1","settingNumber":1},
{"value":150,"color":"red","name":"setting_2","settingNumber":2},
{"value":30,"color":"green","name":"setting_3","settingNumber":3},
{"value":11,"color":"blue","name":"setting_4","settingNumber":4}
]
Illustrated in this jsFiddle: http://jsfiddle/jfriend00/A23Jd/.
The reason I prefer this structure, is you can more easily access the "n" settings as an array of objects:
newData[0].color
newData[0].value
newData[0].name
newData[1].color
....
And, it's easier to iterate through the various settings
Using $.grep will allow you to access the data without mapping them before:
var json={"COLUMNS":["SETTING_NAME","SETTING_VALUE","COLOR"],
"DATA":[["setting_1",100.0,"yellow"],
["setting_2",150.0,"red"],
["setting_3",30.0,"green"],
["setting_4",11.0,"blue"]]}
alert($.grep(json.DATA, function(item){return(item[0]=='setting_4');})[0][2])//returns 'blue'
//or using the labels provided by COLUMNS:
alert($.grep(json.DATA,
function(a){return(a[0]=='setting_4');})[0][$.inArray('COLOR',json.COLUMNS)])
You can do this with a simple for loop:
var obj = {"COLUMNS":["SETTING_NAME","SETTING_VALUE","COLOR"],
"DATA":[["setting_1",100.0,"yellow"],["setting_2",150.0,"red"],
["setting_3",30.0,"green"],["setting_4",11.0,"blue"]]};
for(var i = 0; i < obj.DATA.length; i++)
{
var row = obj.DATA[i]
if (row[0] == 'setting_4')
{
console.log(row[2]);
break;
}
}
Prints:
blue
You could simply reduce that list of DATA:
DATA.reduce(function (value, item) { if (item[0] === "setting_4") return item[2] })
You could wrap that whole thing into a function for easier use, passing in the "setting_4" part. E.g.
var getColour = function (id) {
return DATA.reduce(function (value, item) {
if (item[0] === id) return item[2]
})
}
UPDATE: you could zip the two lists together, perhaps that would make access easier?
obj['DATA'].map(function (row) {
return obj['COLUMNS'].reduce(function (memo, columnName, index) {
memo[columnName] = row[index]
return memo
}, {})
})
This will return something like the following:
[{
COLOR: "yellow",
SETTING_NAME: "setting_1",
SETTING_VALUE: 100
}]
A generic algorithm for translating the dataset into a more-easily-addressed structure.
var json = {
"COLUMNS": [
"SETTING_NAME",
"SETTING_VALUE",
"COLOR"],
"DATA": [
["setting_1",100.0,"yellow"],
["setting_2",150.0,"red"],
["setting_3",30.0,"green"],
["setting_4",11.0,"blue"]
]
};
function translateJSON(json) {
var oHash = {};
var data = json['DATA'];
var cols = json['COLUMNS'];
for(var i = 0, imax = data.length; i < imax; i++) {
var row = data[i]; // shorthand
for(var j = 1, jmax = cols.length; j < jmax; j++) {
var c = cols[j]; // shorthand
oHash[(row[0] + '_' + c.replace(/[^_]+_/, '')).toLowerCase()] = row[j];
}
}
return oHash;
}
var h = translateJSON(json);
console.log(h['setting_4_color']);
Edit: updated the code. translateJSON
will transform the JSON into the data structure you described, for easier property access. If you anticipate needing to access more than one property from the same JSON payload, it will be much more efficient to do a one-time transform before data access than to use something like $.grep
, and much less terse than doing the column-name cross-referencing by hand.
That said, I don't think the target data structure you asked for is necessarily the best one. Assuming you can't change the structure of the JSON payload, it would still probably be better to transform that into something like:
data = {
'setting_1': { 'value': 100.0, 'color': 'yellow' },
'setting_2': { 'value': 150.0, 'color': 'red' }
...
};