2015-11-12 9 views
33

Sfortunatamente, non ho JQuery o Underscore, solo javascript puro (compatibile IE9).Come fare l'equivalente di LINQ SelectMany() solo in javascript

Sto cercando l'equivalente di SelectMany() dalla funzionalità LINQ.

// SelectMany flattens it to just a list of phone numbers. 
IEnumerable<PhoneNumber> phoneNumbers = people.SelectMany(p => p.PhoneNumbers); 

Posso farlo?

EDIT:

Grazie alle risposte, ho ottenuto questo lavoro:

var petOwners = 
[ 
    { 
     Name: "Higa, Sidney", Pets: ["Scruffy", "Sam"] 
    }, 
    { 
     Name: "Ashkenazi, Ronen", Pets: ["Walker", "Sugar"] 
    }, 
    { 
     Name: "Price, Vernette", Pets: ["Scratches", "Diesel"] 
    }, 
]; 

function property(key){return function(x){return x[key];}} 
function flatten(a,b){return a.concat(b);} 

var allPets = petOwners.map(property("Pets")).reduce(flatten,[]); 

console.log(petOwners[0].Pets[0]); 
console.log(allPets.length); // 6 

var allPets2 = petOwners.map(function(p){ return p.Pets; }).reduce(function(a, b){ return a.concat(b); },[]); // all in one line 

console.log(allPets2.length); // 6 
+3

Questo non è sfortunato affatto. JavaScript puro è sorprendente. Senza contesto, è molto difficile capire cosa stai cercando di ottenere qui. –

+0

@SterlingArcher, guarda come si è rivelata la risposta. Non ci sono state troppe risposte possibili e la risposta migliore è stata breve e concisa. – toddmo

risposta

43

per un semplice selezioni è possibile utilizzare la funzione di ridurre di Array.
Diciamo che avere un array di array di numeri:

var arr = [[1,2],[3, 4]]; 
arr.reduce(function(a, b){ return a.concat(b); }); 
=> [1,2,3,4] 

var arr = [{ name: "name1", phoneNumbers : [5551111, 5552222]},{ name: "name2",phoneNumbers : [5553333] }]; 
arr.map(function(p){ return p.phoneNumbers; }) 
    .reduce(function(a, b){ return a.concat(b); }) 
=> [5551111, 5552222, 5553333] 
+0

Quest'ultimo può anche essere scritto come 'arr.reduce (function (a, b) {return a.concat (b.phoneNumbers);}, [])' – Timwi

4

Sagi è corretto utilizzando il metodo concat per appiattire un array. Ma per ottenere qualcosa di simile a questo esempio, si sarebbe anche bisogno di una mappa per la parte di selezione https://msdn.microsoft.com/library/bb534336(v=vs.100).aspx

/* arr is something like this from the example PetOwner[] petOwners = 
        { new PetOwner { Name="Higa, Sidney", 
          Pets = new List<string>{ "Scruffy", "Sam" } }, 
         new PetOwner { Name="Ashkenazi, Ronen", 
          Pets = new List<string>{ "Walker", "Sugar" } }, 
         new PetOwner { Name="Price, Vernette", 
          Pets = new List<string>{ "Scratches", "Diesel" } } }; */ 

function property(key){return function(x){return x[key];}} 
function flatten(a,b){return a.concat(b);} 

arr.map(property("pets")).reduce(flatten,[]) 
+0

I '; sto andando a fare un violino; Posso usare i tuoi dati come json. Cercherò di appiattire la risposta a una riga di codice. "Come appiattire una risposta sull'appiattimento delle gerarchie degli oggetti" lol – toddmo

+0

Sentitevi liberi di usare i vostri dati ... Ho estrapolato esplicitamente la funzione mappa in modo da poter facilmente selezionare qualsiasi nome di proprietà senza dover scrivere una nuova funzione ogni volta. Basta sostituire 'arr' con' people' e '" pets "' con '" PhoneNumbers "' –

+0

Ho modificato la mia domanda con la versione appiattita e ho votato la tua risposta. Grazie. – toddmo

3
// you can save this function in a common js file of your project 
function selectMany(f){ 
    return function (acc,b) { 
     return acc.concat(f(b)) 
    } 
} 

var ex1 = [{items:[1,2]},{items:[4,"asda"]}]; 
var ex2 = [[1,2,3],[4,5]] 
var ex3 = [] 
var ex4 = [{nodes:["1","v"]}] 

Cominciamo

ex1.reduce(selectMany(x=>x.items),[]) 

=> [1, 2, 4, " asda "]

ex2.reduce(selectMany(x=>x),[]) 

=> [1, 2, 3, 4, 5]

ex3.reduce(selectMany(x=> "this will not be called"),[]) 

=> []

ex4.reduce(selectMany(x=> x.nodes),[]) 

=> [ "1", "v"]

NOTA: utilizzare dell'array valida (non nulla) come valore intitial nella funzione ridurre

1

Per quelli un po 'più tardi, la comprensione javascript ma vuole ancora un metodo semplice tipizzata SelectMany a macchina:

function selectMany<TIn, TOut>(input: TIn[], selectListFn: (t: TIn) => TOut[]): TOut[] { 
    return input.reduce((out, inx) => { 
    out.push(...selectListFn(inx)); 
    return out; 
    }, new Array<TOut>()); 
} 
Problemi correlati