2015-11-12 9 views
33

Niestety, nie mam JQuery ani Underscore, tylko czysty javascript (zgodny z IE9).Jak wykonać odpowiednik LINQ SelectMany() właśnie w javascript

Potrzebuję ekwiwalentu SelectMany() z funkcji LINQ.

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

Czy mogę to zrobić?

EDIT:

Dzięki odpowiedzi, dostałem tej pracy:

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

To wcale nie jest niefortunne. Czysta JavaScript jest niesamowita. Bez kontekstu bardzo trudno jest zrozumieć, co próbujesz osiągnąć tutaj. –

+0

@SterlingArcher, zobacz, jak konkretna okazała się odpowiedź. Nie było zbyt wielu możliwych odpowiedzi, a najlepsza odpowiedź była krótka i zwięzła. – toddmo

Odpowiedz

43

na prostą wybrać można użyć funkcji redukcji Array.
Powiedzmy, że masz tablicę tablic liczb:

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

To ostatnie może być zapisana jako 'arr.reduce (funkcja (a, b) {powrotnej a.concat (b.phoneNumbers)}, [])' – Timwi

4

Sagi słusznie stosując metodę concat spłaszczyć tablicę. Jednak, aby uzyskać coś podobnego do tego przykładu, będzie trzeba także mapę dla wybranej części 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 "M będzie dokonać skrzypce; Mogę wykorzystać twoje dane jako json. Spróbuje spłaszczyć twoją odpowiedź do jednej linii kodu. „Jak spłaszczyć odpowiedź o spłaszczenie hierarchii obiektów” lol – toddmo

+0

Zapraszamy do korzystania z danych ... I explictly wydobywane funkcji map, dzięki czemu można łatwo wybrać dowolną nazwę właściwości bez konieczności pisania nowej funkcji za każdym razem. Po prostu zamień 'arr' na' people' i '" pets "' z '" PhoneNumbers "' –

+0

Edytowałem moje pytanie w wersji spłaszczonej i głosowałem na twoją odpowiedź w górę. Dzięki. – 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"]}] 

Zacznijmy

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"]

UWAGA: stosować poprawnej tablicy (nie zerowy) jako wartość intitial w funkcji zmniejszenia

1

Dla tych, chwilę później, rozumiejąc JavaScript, ale nadal chcą prostą metodę Wpisane SelectMany na maszynie:

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