-
-
Save samgiles/762ee337dff48623e729 to your computer and use it in GitHub Desktop.
// [B](f: (A) ⇒ [B]): [B] ; Although the types in the arrays aren't strict (: | |
Array.prototype.flatMap = function(lambda) { | |
return Array.prototype.concat.apply([], this.map(lambda)); | |
}; |
Thank you very much! :)
Haven't benchmarked. But this is my implementation in typescript.
function flatMap<T, U>(array: T[], mapFunc: (x: T) => U[]) : U[] {
return array.reduce((cumulus: U[], next: T) => [...mapFunc(next), ...cumulus], <U[]> []);
}
How it differs from this?
Array.prototype.flatMap = function(lambda) {
return [].concat(this.map(lambda));
};
@ixth I think you must use apply()
in order to convert the returned array of map()
into the arguments of concat()
:
Array.prototype.flatMap = function(lambda) {
return [].concat.appy([],this.map(lambda));
};
Without touching the prototype :
[0, 1, 2, 3, 4, 5].reduce((list,x) => list.concat([x, x+1]), []);
// [0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6]
Here is a bit of shorter way using es6 spread, similiar to renaudtertrais's - but using es6 and not adding to the prototype.
var flatMap = (a, cb) => [].concat(...a.map(cb))
const s = (v) => v.split(',')
const arr = ['cat,dog', 'fish,bird']
flatMap(arr, s)
To avoid adding an enumerable property (which will break all for (var i in []) {}
statements, this adds the function as a non-enumerable property
Object.defineProperties(Array.prototype, {
'flatMap': {
value: function (lambda) {
return Array.prototype.concat.apply([], this.map(lambda));
},
writeable: false,
enumerable: false
}
});
@AWilco +1. Note that writeable
and enumerable
both default to false
, so you can leave those off.
Same implementation as @dsacramone with added TypeScript type annotations.
Note that mapping function can also use index
and original array
.
function flatMap<T, U>(array: T[], callbackfn: (value: T, index: number, array: T[]) => U[]): U[] {
return [].concat(...array.map(callbackfn));
}
Not mentioned is that you should never modify prototypes of default objects, which this code perfectly failed to do.
If the stunt is performed by trained professionals that can be acceptable
For optimization, don't use concat use : push.apply
@Ran-P JSPerf begs to differ, for me at least https://jsperf.com/array-prototype-push-apply-vs-concat/13
@ichpuchtli I like it, but isn't the order of the concatenation backwards?
@dsacramone gets my vote for most concise and readable, tho :)
If you need to work with deeply nested arrays:
const myArray = [[1, 2],[3, [4, [5, 6]]], [7, [8, 9]]];
const flatMapDeep = (value, mapper) => {
return Array.isArray(value) ?
[].concat(...value.map(x => flatMapDeep(x, mapper))) :
mapper(value);
}
const mapper = (x) => x * 11;
const flatArray = flatMapDeep(myArray, mapper); // [11, 22, 33, 44, 55, 66, 77, 88, 99]
const flatMap = (a, f) => a.map(f).reduce((xs, ys) => [...xs, ...ys]); // using map first to avoid recursion in reduce
[1, 2, 3].map(x => [x, x + 1]); // => [[1, 2], [2, 3], [3, 4]]
flatMap([1, 2, 3], x => [x, x + 1]); // => [1, 2, 2, 3, 3, 4]
/*
recursive methods (at least obvious ones) are for chumps! lets do some string manipulation instead...
works, assuming your array does not actually includes "[" or "]" characters ¯\(◉◡◔)/¯
*/
Array.prototype.cheeky_flatMap = function(){
return JSON.parse( "["
+ JSON.stringify(this)
.replace(/[\[\]\,]+/g,",")
.replace(/(^\,|\,$)/g,"")
+ "]"
);
}
Also, works in any depth...
cheeky_flatmap([[1,2],[3,4],[[[5]]]])
- [1,2,3,4,5]
Example