Unfortunately, I don\'t have JQuery or Underscore, just pure javascript (IE9 compatible).
I\'m wanting the equivalent of SelectMany() from LINQ functionality.
<As a simpler option Array.prototype.flatMap() or 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.flatMap(a => a.details); // or 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"]}]
Let's start
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
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 { };
I would do this (avoiding .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]
If you don't want to use .reduce():
function SelectMany(array, arr = []) {
for (let item of array) {
if (item && item.length)
arr = SelectMany(item, arr);
else
arr.push(item);
}
return arr;
}
If you want to use .forEach():
function SelectMany(array, arr = []) {
array.forEach(e => {
if (e && e.length)
arr = SelectMany(e, arr);
else
arr.push(e);
});
return arr;
}
For those a while later, understanding javascript but still want a simple Typed SelectMany method in Typescript:
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>());
}
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)