如何做相当于 LINQSelectmany()只是在 javascript

不幸的是,我没有 JQuery 或下划线,只有纯 javascript (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
66089 次浏览

对于一个简单的选择,您可以使用 Array 的 reduce 函数。
假设您有一个数字数组数组:

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]

编辑:
因为 es6 latMap 已经被添加到 Array 原型中。 SelectManyflatMap的同义词。
该方法首先使用映射函数映射每个元素,然后将结果平坦化为一个新数组。 它在 TypeScript 中的简化签名是:

function flatMap<A, B>(f: (value: A) => B[]): B[]

为了完成这个任务,我们只需要将每个元素平面映射到 phoneNumbers

arr.flatMap(a => a.phoneNumbers);

Sagi 使用 concat 方法展开数组是正确的。但是要获得类似于此示例的内容,您还需要选择部分的映射 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,[])
// 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”]

注意: 在 reduce 函数中使用有效数组(非空)作为初始值

对于那些稍后会理解 javascript,但仍然需要一个简单的 Type 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.SelectMany = function (keyGetter) {
return this.map(x=>keyGetter(x)).reduce((a, b) => a.concat(b));
}

示例数组:

 var juices=[
{key:"apple",data:[1,2,3]},
{key:"banana",data:[4,5,6]},
{key:"orange",data:[7,8,9]}
]

使用:

juices.SelectMany(x=>x.data)

作为一个简单的选项 Prototype.latMap ()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.flatMap(a => a.details); // or data.map(a => a.details).flat(1);
console.log(result)

您可以尝试实现所有 C # LINQ 方法并保留其语法的 manipula包:

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

Https://github.com/litichevskiydv/manipula

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

这是 Joel-harkes 答案的重写版本,用 TypeScript 作为扩展,可用于任何数组。所以你可以像使用 somearray.selectMany(c=>c.someprop)一样使用它。这是 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 { };

我会这样做(避免. concat ()) :

function SelectMany(array) {
var flatten = function(arr, e) {
if (e && e.length)
return e.reduce(flatten, arr);
else
arr.push(e);
return arr;
};


return array.reduce(flatten, []);
}


var nestedArray = [1,2,[3,4,[5,6,7],8],9,10];
console.log(SelectMany(nestedArray)) //[1,2,3,4,5,6,7,8,9,10]

如果你不想使用. reduce () :

function SelectMany(array, arr = []) {
for (let item of array) {
if (item && item.length)
arr = SelectMany(item, arr);
else
arr.push(item);
}
return arr;
}

如果要使用. forEach () :

function SelectMany(array, arr = []) {
array.forEach(e => {
if (e && e.length)
arr = SelectMany(e, arr);
else
arr.push(e);
});


return arr;
}

对于 JavaScript 的后续版本,你可以这样做:

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


var arrayOfArrays = petOwners.map(po => po.Pets);
var allPets = [].concat(...arrayOfArrays);


console.log(allPets); // ["Scruffy","Sam","Walker","Sugar","Scratches","Diesel"]

参见 例如 StackBlitz