code

JavaScript에서 LINQ SelectMany ()와 동등한 작업을 수행하는 방법

codestyles 2020. 11. 24. 08:00
반응형

JavaScript에서 LINQ SelectMany ()와 동등한 작업을 수행하는 방법


불행히도 JQuery 나 Underscore가없고 순수한 자바 스크립트 (IE9 호환) 만 있습니다.

LINQ 기능에서 SelectMany ()에 해당하는 것을 원합니다.

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

할 수 있습니까?

편집하다:

답변 덕분에 다음과 같이 작동했습니다.

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

간단한 선택을 위해 Array의 축소 기능을 사용할 수 있습니다.
숫자 배열이 있다고 가정 해 보겠습니다.

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]

배열을 평면화하기 위해 concat 메서드를 사용하면 Sagi가 정확합니다. 그러나이 예제와 유사한 것을 얻으려면 선택 부분 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,[])

잠시 후 자바 스크립트를 이해하지만 Typescript에서 간단한 Typed SelectMany 메서드를 원합니다.

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

더 간단한 옵션으로 Array.prototype.flat ()

const data = [
{id: 1, name: 'Dummy Data1', details: [{id: 1, name: 'Dummy Data1 Details'}, {id: 1, name: 'Dummy Data1 Details2'}]},
{id: 1, name: 'Dummy Data2', details: [{id: 2, name: 'Dummy Data2 Details'}, {id: 1, name: 'Dummy Data2 Details2'}]},
{id: 1, name: 'Dummy Data3', details: [{id: 3, name: 'Dummy Data3 Details'}, {id: 1, name: 'Dummy Data3 Details2'}]},
]

const result = data.map(a => a.details).flat(1);
console.log(result)


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

시작하자

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

NOTE: use valid array (non null) as intitial value in the reduce function


try this (with es6):

Array.prototype.SelectMany = function (keyGetter) {
return this.map(x=>keyGetter(x)).reduce((a, b) => a.concat(b)); 
}

example array :

var juices=[

{key:"apple",data:[1,2,3]},

{key:"banana",data:[4,5,6]},

{key:"orange",data:[7,8,9]}

]

using :

juices.SelectMany(x=>x.data)


You can try the manipula package that implements all C# LINQ methods and preserves its syntax:

Manipula.from(petOwners).selectMany(x=>x.Pets).toArray()

https://github.com/litichevskiydv/manipula

https://www.npmjs.com/package/manipula


Here you go, a rewritten version of joel-harkes' answer in TypeScript as an extension, usable on any array. So you can literally use it like `somearray.selectMany(c=>c.someprop). Trans-piled, this is javascript.

declare global {
    interface Array<T> {
        selectMany<TIn, TOut>(selectListFn: (t: TIn) => TOut[]): TOut[];
    }
}

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


export { };

참고URL : https://stackoverflow.com/questions/33679850/how-to-do-equivalent-of-linq-selectmany-just-in-javascript

반응형