2012-11-13 10 views
9

In JavaScript Sto cercando di convertire un array di oggetti con i tasti simili:Come trasporre oggetto in underscorejs

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

ad un oggetto con una serie di valori per ogni chiave:

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

using underscore.js 1.4.2.

Ho un codice funzionante di seguito, ma ci si sente più a lungo e più clunkier che scrivere annidato per loop.

C'è un modo più elegante per farlo in underscore? C'è qualcosa di semplice che mi manca?

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)); 

Grazie

risposta

8

Sembra che si desidera zip per gli oggetti. Questo sarebbe il metodo analogous per gli oggetti:

_.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; 
}; 

Tuttavia, vorrei solo usare

_.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; 
}; 

senza alcuna sottolineatura a tutti :-) Naturalmente, è possibile utilizzare alcuni metodi iteratore, allora potrebbe assomigliare

_.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, grazie. In realtà, quello non è stato il mio unico errore: -/ – Bergi

+0

@Berg: Grazie molto completo. Ti spiace se apro un ticket su underscore github per includere una funzione transpose e usare la tua risposta come esempio? –

+0

Oh e la riduzione annidata è ciò che stavo cercando di scrivere, penso. –

0

avete bisogno di 3 linee di lodash:

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

Vedi the docs of _.merge per maggiori dettagli su ciò che la funzione fa.

Problemi correlati