2012-09-10 9 views
41

Imagine que tengo una estructura de matriz anidada.¿Cuál es el equivalente de underscore.js al operador SelectMany de LINQ?

var nested = [ [1], [2], [3] ]; 

Usando underscore.js, ¿cómo iba a producir una matriz plana?

En C# que usaría Enumerable.SelectMany así:

var flattened = nested.SelectMany(item => item); 

Tenga en cuenta que la lambda en este caso, se accede directamente el elemento anidado, pero podría haber sido cualquier expresión arbitraria.

En jQuery, es posible utilizar simplemente:

var flattened = $.map(nested, function(item) { return item; }); 

Sin embargo, este enfoque no funciona con la función de subrayado map.

Entonces, ¿cómo obtendría la matriz aplanada [1, 2, 3] usando underscore.js?

+3

uso _.flatten? – yngccc

+0

también podría escribir: _.map (anidado, función (elemento) {elemento devuelto [0];}) – Darragh

+0

@Darragh, eso funcionaría para mi ejemplo específico, pero no cuando los arrays secundarios contienen elementos múltiples. –

Respuesta

35
var nested = [ [1], [2], [3] ]; 
var flattened = _.flatten(nested); 

Heresa fiddle

+0

¡Agradable y fácil! ¿Por qué no lo vi en su documentación?:) –

+6

Aviso: pase superficial = verdadero, si solo desea un nivel de aplanamiento (como SelectMany): '_.flatten (anidado, verdadero)' –

+2

['flatten'] (https://lodash.com/docs #flatten) parece hacer solo un nivel por defecto ahora; han agregado 'flattenDeep' y' flattenDepth'. – mpen

37

Si usted tiene una gama un poco más complicado, por ejemplo uno que viene de JSON, puede tomar ventaja del método pluck así, la extracción de la propiedad específica le interesa, de manera similar a parents.SelectMany(parent => parent.Items);

// underscore version 
var allitems = _.flatten(_.pluck(parents, 'items')); 

allitems es ahora el conjunto de todos los subelementos de los padres, [a,b,c,d].

Y un JSFiddle mostrando lo mismo.


O, si está utilizando lodash se puede hacer lo mismo mediante el uso de la función _.flatMap que está disponible desde la versión 4. Cred a Noel por señalarlo en los comentarios.

var parents = [ 
 
    { name: 'hello', items: ['a', 'b'] }, 
 
    { name: 'world', items: ['c', 'd'] } 
 
]; 
 

 

 
// version 1 of lodash, straight up 
 
var allitems = _.flatMap(parents, 'items'); 
 
logIt('straight', allitems); 
 

 
// or by wrapping the collection first 
 
var allitems = _(parents) 
 
    .flatMap('items') 
 
    .value(); 
 
logIt('wrapped', allitems); 
 

 
// this basically does _(parents).map('items').flatten().value(); 
 

 
function logIt(wat, value) { 
 
    document.getElementById('result').innerHTML += wat + ':' + JSON.stringify(value) + '\r\n<br/>'; 
 
}
<script src="https://cdn.jsdelivr.net/lodash/4.16.6/lodash.min.js"></script> 
 
<div id="result"></div>

+1

Aunque no está disponible en guión bajo, con lodash, usted podría simplificar el uso de 'map' y' flatten' para usar solo 'flatMap', así:' _.flatMap (parents, "items") '). – Noel

+0

Gracias @Noel, lo agregaré a mi respuesta. No sabía sobre eso cuando escribí mi respuesta – Patrick

2

no pude encontrar ningún método en lodash que funcionan bastante como SelectMany, así que creó uno utilizando JS puros:

Array.prototype.selectMany = function(fn) { 
    return Array.prototype.concat(...this.map(fn)); 
}; 

Boom.

> console.log([{a:[1,2],b:'x'},{a:[3,4],b:'y'}].selectMany(o => o.a)); 
[ 1, 2, 3, 4 ] 
+0

¿De verdad? He incluido una muestra de trabajo en mi respuesta. ¿Qué pasa con esa solución? – Patrick

+0

@Patrick El orden de las operaciones. Se vuelve confuso cuando hay anidamiento: 'a.selectMany (b => b.c.selectMany (d => d.e))'. Intenta volver a escribir eso usando tu solución. – mpen

3

También podemos hacer Patrick's solution en un mixin para que se convierta chainable:

_.mixin({ 
    selectMany: function(collection, iteratee=_.identity) { 
     return _.flatten(_.map(collection, iteratee)); 
    } 
}); 

Ejemplos:

let sample = [{a:[1,2],b:'x'},{a:[3,4],b:'y'}]; 

console.log(_.selectMany(sample, 'a')); // [ 1, 2, 3, 4 ] 
console.log(_.chain(sample).selectMany(o => o.a).filter(a => a % 2 === 0).map(a => a * 3).value()); // [ 6, 12 ] 
Cuestiones relacionadas