2012-09-06 273 views
4

從服務中,我收到一個帶有鍵值對的JSON對象,我需要從它們動態地創建對象,按一列分組。從鍵值對創建對象數組

的JSON看起來像這樣:

[ 
    { "Group" : "A", "Key" : "Name", "Value" : "John" }, 
    { "Group" : "A", "Key" : "Age", "Value" : "30" }, 
    { "Group" : "A", "Key" : "City", "Value" : "London" }, 
    { "Group" : "B", "Key" : "Name", "Value" : "Hans" }, 
    { "Group" : "B", "Key" : "Age", "Value" : "35" }, 
    { "Group" : "B", "Key" : "City", "Value" : "Berlin" }, 
    { "Group" : "C", "Key" : "Name", "Value" : "José" }, 
    { "Group" : "C", "Key" : "Age", "Value" : "25" }, 
    { "Group" : "C", "Key" : "City", "Value" : "Madrid" } 
] 

我需要將其轉換到以下對象數組:

[ 
    { Group : "A", Name : "John", Age : 30, City : "London" }, 
    { Group : "B", Name : "Hans", Age : 35, City : "Berlin" }, 
    { Group : "C", Name : "José", Age : 25, City : "Madrid" } 
] 

每個組可以包含任意數量的鍵 - 值對。

目前我對這個工作的解決方案,但我不知道這是否是最佳的:

var items = [ 
    { "Group" : "A", "Key" : "Name", "Value" : "John" }, 
    { "Group" : "A", "Key" : "Age", "Value" : "30" }, 
    { "Group" : "A", "Key" : "City", "Value" : "London" }, 
    { "Group" : "B", "Key" : "Name", "Value" : "Hans" }, 
    { "Group" : "B", "Key" : "Age", "Value" : "35" }, 
    { "Group" : "B", "Key" : "City", "Value" : "Berlin" }, 
    { "Group" : "C", "Key" : "Name", "Value" : "José" }, 
    { "Group" : "C", "Key" : "Age", "Value" : "25" }, 
    { "Group" : "C", "Key" : "City", "Value" : "Madrid" } 
], item, record, hash = {}, results = []; 

// Create a "hash" object to build up 
for (var i = 0, len = items.length; i < len; i += 1) { 
    item = items[i]; 

    if (!hash[item.Group]) { 
    hash[item.Group] = { 
     Group : item.Group 
    }; 
    } 
    hash[item.Group][item.Key] = item.Value; 
} 

// Push each item in the hash to the array 
for (record in hash) { 
    if(hash.hasOwnProperty(record)) { 
    results.push(hash[record]); 
    } 
} 

您可以檢查這裏的小提琴:http://jsbin.com/ozizom/1/

你對此有一個更好的解決方案?

+0

按照你的例子,JSON是否總是按Group排序? – sp00m

+0

是的,JSON字段組,鍵和值給出,並且記錄總是按組排序 – tpolyak

回答

5

假設JSON記錄將始終按組進行排序,這裏是另一種方法:

var json = [ 
    { "Group" : "A", "Key" : "Name", "Value" : "John" }, 
    { "Group" : "A", "Key" : "Age", "Value" : "30" }, 
    { "Group" : "A", "Key" : "City", "Value" : "London" }, 
    { "Group" : "B", "Key" : "Name", "Value" : "Hans" }, 
    { "Group" : "B", "Key" : "Age", "Value" : "35" }, 
    { "Group" : "B", "Key" : "City", "Value" : "Berlin" }, 
    { "Group" : "C", "Key" : "Name", "Value" : "José" }, 
    { "Group" : "C", "Key" : "Age", "Value" : "25" }, 
    { "Group" : "C", "Key" : "City", "Value" : "Madrid" } 
]; 

var array = []; 
var previousGroup = null; 

for(var i=0; i<json.length; i++) { 
    var group = json[i].Group; 
    if(previousGroup != group) { 
     array.push({Group: group}); 
     previousGroup = group; 
    } 
    array[array.length-1][json[i].Key] = json[i].Value; 
} 

Here是一個工作的例子。

+0

謝謝,它比我的快50%:http://jsperf.com/javascript-key-value – tpolyak

+0

我沒有知道jsperf.com,這真棒!感謝你;) – sp00m

+0

雖然發現了一個問題。只有當羣組按順序到達時(AAABBBCCC),您的解決方案才能正常工作。例如如果訂單是AAABBCCCB,則創建4條記錄:http://jsfiddle.net/GrmZF/2/ – tpolyak

3

下面是一個解決方案,通過使用JavaScript成語縮減代碼大小(對於更好或更糟:-)。該解決方案不依賴輸入值的順序:

var values = [ 
    {Group: 'A', Key: 'Name', Value: 'John'}, 
    {Group: 'A', Key: 'Age', Value: '30'}, 
    {Group: 'A', Key: 'City', Value: 'London'}, 
    {Group: 'B', Key: 'Name', Value: 'Hans'}, 
    {Group: 'B', Key: 'Age', Value: '35'}, 
    {Group: 'B', Key: 'City', Value: 'Berlin'}, 
    {Group: 'C', Key: 'Name', Value: 'José'}, 
    {Group: 'C', Key: 'Age', Value: '25'}, 
    {Group: 'C', Key: 'City', Value: 'Madrid'} 
]; 

var map = {}; 
values.forEach(function(value) { 
    map[value.Group] = map[value.Group] || {Group: value.Group}; 
    map[value.Group][value.Key] = value.Value; 
}); 

var results = Object.keys(map).map(function(key) { return map[key]; }); 

工作示例是在http://jsfiddle.net/arQww

這裏是最快的解決方案,我可以找到,其假定值將始終按組進行排序:

var group, results = []; 
for (var i = 0; i < values.length;) { 
    results.push({Group: group = values[i].Group}); 
    do { 
    results.push[results.length - 1][values[i].Key] = values[i].Value; 
    } while (++i < values.length && values[i].Group == group); 
} 

的性能對比是http://jsperf.com/vnmzc。雖然第二種解決方案更快,但兩者的性能都是O(n),而它們之間的現實差異將是無關緊要的,所以第一種解決方案可能更好,因爲它更簡單,更通用。

-1

我需要類似問題的幫助,購買我想總結價值。我有這個數組與對象

var myArrWithObj = [ 
    {DateToSort: "Jul2014", ValueOneToSum: "60", ValueTwoToSum: "15"}, 
    {DateToSort: "Jul2014", ValueOneToSum: "30", ValueTwoToSum: "50"}, 
    {DateToSort: "Jul2014", ValueOneToSum: "12", ValueTwoToSum: "22"}, 
    {DateToSort: "Aug2014", ValueOneToSum: "65", ValueTwoToSum: "25"}, 
    {DateToSort: "Aug2014", ValueOneToSum: "13", ValueTwoToSum: "10"}, 
    {DateToSort: "Aug2014", ValueOneToSum: "90", ValueTwoToSum: "20"}, 
    {DateToSort: "Sep2014", ValueOneToSum: "60", ValueTwoToSum: "15"}, 
    {DateToSort: "Sep2014", ValueOneToSum: "60", ValueTwoToSum: "18"}, 
    {DateToSort: "Sep2014", ValueOneToSum: "75", ValueTwoToSum: "18"} 
        ]; 

我希望用戶選擇從一個選項菜單中總結的月份。

因此,如果用戶從選擇菜單,我要總結的所有ValueOneToSum值,並根據Aug2014ValueTwoToSum值,我怎麼能做到這一點選擇August 2014

例如:totalSumOneAug2014168totalSumTwo55

1

如果你不得不操縱數據,我會推薦underscore框架。 這就是解決方案的外觀:

/* 
We group items into object that looks like {group: attributes, ..} 
Then for each group we create result object denoting group, 
and extend result with object created from keys and values of attributes 
*/ 
_.map(_.groupBy(items, function (item) {return item.Group}), 
    function (attributes, group) { 
     return _.extend({Group: group}, 
         _.object(_.pluck(attributes, 'Key'), 
           _.pluck(attributes, 'Value'))) 
    })