2012-11-13 32 views
9

Trong JavaScript Tôi cố gắng để chuyển đổi một mảng của các đối tượng với các phím tương tự:Làm thế nào để transpose đối tượng trong underscorejs

[{'a':1,'b':2}, {'a':3,'b':4}, {'a':5,'b':6,'c':7}] 

đến một đối tượng với một mảng các giá trị cho mỗi phím:

{'a':[1,3,5], 'b':[2,4,6], 'c':[7]}; 

sử dụng underscore.js 1.4.2.

Tôi có một số mã hoạt động bên dưới, nhưng nó cảm thấy dài hơn và clunkier hơn là chỉ viết lồng nhau cho vòng lặp.

Có cách nào thanh lịch hơn để thực hiện việc này dưới dấu gạch dưới không? Có cái gì đơn giản tôi đang mất tích?

console.clear(); 

var input = [{'a':1,'b':2},{'a':3,'b':4},{'a':5,'b':6,'c':7}]; 
var expected = {'a':[1,3,5], 'b':[2,4,6], 'c':[7]}; 

// Ok, go 
var output = _(input) 
.chain() 
// Get all object keys 
.reduce(function(memo, obj) { 
    return memo.concat(_.keys(obj)); 
}, []) 
// Get distinct object keys 
.uniq() 
// Get object key, values 
.map(function(key) { 
    // Combine key value variables to an object 
    // ([key],[[value,value]]) -> {key: [value,value]} 
    return _.object(key,[ 
     _(input) 
     .chain() 
     // Get this key's values 
     .pluck(key) 
     // Filter out undefined 
     .compact() 
     .value() 
    ]); 
}) 
// Flatten array of objects to a single object 
// [{key1: [value]}, {key2, [values]}] -> {key1: [values], key2: [values]} 
.reduce(function(memo, obj) { 
    return _.extend(memo, obj); 
}, {}) 
.value(); 

console.log(output); 
console.log(expected); 
console.log(_.isEqual(output, expected)); 

Cảm ơn

Trả lời

8

Âm thanh như bạn muốn zip cho các đối tượng. Đây sẽ là phương pháp analogous cho các đối tượng:

_.transpose = function(array) { 
    var keys = _.union.apply(_, _.map(array, _.keys)), 
     result = {}; 
    for (var i=0, l=keys.length; i<l; i++) { 
     var key = keys[i]; 
     result[key] = _.pluck(array, key); 
    } 
    return result; 
}; 

Tuy nhiên, tôi sẽ chỉ sử dụng

_.transpose = function(array) { 
    var result = {}; 
    for (var i=0, l=array.length; i<l) 
     for (var prop in array[i]) 
      if (prop in result) 
       result[prop].push(array[i][prop]); 
      else 
       result[prop] = [ array[i][prop] ]; 
    return result; 
}; 

mà không cần bất kỳ dấu gạch dưới ở tất cả :-) Tất nhiên, bạn có thể sử dụng một số phương pháp lặp, nó sau đó có thể trông giống như

_.reduce(array, function(map, obj) { 
    return _.reduce(obj, function(map, val, key) { 
     if (key in map) 
      map[key].push(val) 
     else 
      map[key] = [val]; 
     return map; 
    }, map); 
}, {}); 
+0

Ah, cảm ơn. Trên thực tế, đó không phải là sai lầm duy nhất của tôi: -/ – Bergi

+0

@Bergi: Cảm ơn thats khá toàn diện. Bạn có phiền nếu tôi mở một vé trên github gạch dưới để bao gồm một chức năng transpose và sử dụng câu trả lời của bạn như là một ví dụ? –

+0

Oh và giảm lồng nhau là những gì tôi đã cố gắng để viết tôi nghĩ. –

0

Bạn cần 3 dòng lodash:

_.merge.apply(null, _.union([{}], myArrayOfObjects, [function (a, b) { 
    return _.compact(_.flatten([a, b])); 
}])) 

Xem the docs of _.merge để biết thêm chi tiết về những gì các chức năng thực hiện.