2012-11-13 14 views
9

W JavaScript Próbuję przekonwertować tablicę obiektów o podobnej klawiszy:Jak przenieść obiekt w underscore.js

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

do obiektu z tablicą wartości dla każdego klucza:

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

przy użyciu pliku underscore.js 1.4.2.

Mam poniżej działający kod, ale wydaje się dłuższy i bardziej zagęszczony niż pisanie zagnieżdżone dla pętli.

Czy jest bardziej elegancki sposób robienia tego w podkreślniku? Czy jest coś prostego, czego mi brakuje?

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

Dzięki

Odpowiedz

8

Brzmi jak chcesz zip dla obiektów. Byłby to metoda analogous dla obiektów:

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

Chciałbym jednak wystarczy użyć

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

bez podkreślenia w ogóle :-) Oczywiście, można użyć niektóre metody iteracyjnej, to wówczas może wyglądać

_.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, dzięki. Właściwie to nie był mój jedyny błąd: -/ – Bergi

+0

@Bergi: Dzięki temu jest całkiem obszerny. Czy przeszkadza mi, jeśli otworzę bilet na podkreślenie github, aby włączyć funkcję transpozycji i jako odpowiedzi posłużyć się twoją odpowiedzią? –

+0

Aha i to, co próbowałem napisać, to myślenie zagnieżdżone. –

0

Trzeba 3 linie lodash:

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

Zobacz the docs of _.merge więcej szczegółów na temat tego, co robi funkcja.

Powiązane problemy