flatMapє неймовірно корисним для колекцій, але javascript не надає такого, маючи Array.prototype.map. Чому?
Чи є спосіб емуляції flatMapв javascript як простим, так і ефективним способом без визначення flatMapвручну?
flatMapє неймовірно корисним для колекцій, але javascript не надає такого, маючи Array.prototype.map. Чому?
Чи є спосіб емуляції flatMapв javascript як простим, так і ефективним способом без визначення flatMapвручну?
arr.map(...).reduce(...)).
Відповіді:
Оновлення: Array.prototype.flatMap на шляху до рідного ECMAScript. На даний момент це на етапі 4 .
Він широко підтримується в багатьох середовищах. Перевірте, чи працює це у вашому браузері, використовуючи цей фрагмент нижче -
const data =
[ 1, 2, 3, 4 ]
console.log(data.flatMap(x => Array(x).fill(x)))
// [ 1, 2, 2, 3, 3, 3, 4, 4, 4, 4 ]
Чому в JavaScript немає Array.prototype.flatMap?
Оскільки програмування не є магією, і кожна мова не має властивостей / примітивів, якими володіє кожна інша мова
Важливим є
JavaScript дає вам можливість самостійно визначити його
const concat = (x,y) =>
x.concat(y)
const flatMap = (f,xs) =>
xs.map(f).reduce(concat, [])
const xs = [1,2,3]
console.log(flatMap(x => [x-1, x, x+1], xs))
Або перезапис, який згортає дві петлі в одну
const flatMap = (f,xs) =>
xs.reduce((acc,x) =>
acc.concat(f(x)), [])
const xs = [1,2,3]
console.log(flatMap(x => [x-1, x, x+1], xs))
Якщо ви хочете, щоб це було на Array.prototype, вас ніщо не заважає
const concat = (x, y) => x.concat(y)
const flatMap = (f, xs) => xs.map(f).reduce(concat, [])
if (Array.prototype.flatMap === undefined) {
Array.prototype.flatMap = function(f) {
return flatMap(f, this)
}
}
const xs = [1, 2, 3]
console.log(xs.flatMap(x => [x-1, x, x+1]))
.as-console-wrapper { top: 0; max-height: 100% !important; }
Array.prototype._mylib_flatMap), або навіть краще використовувати символи ES6, а не просто визначати Array.prototype.flatMap.
mapвизначеною як глобальна функція! По-друге, це просто погана практика
append, map, filter, foldl, foldrсеред незліченних інших в просторі імен за замовчуванням. Це не робить це поганою практикою, тому що ви чули, як хтось каже "глобали погані" або "розширення корінних жителів це погано" - рекет є однією з найкращих мов. Ви просто не знаєте, як / коли це зробити належним чином.
flatMapбув затверджений TC39 як частина ES2019 (ES10). Ви можете використовувати його так:
[1, 3].flatMap(x => [x, x + 1]) // > [1, 2, 3, 4]
Ось моя власна реалізація методу:
const flatMap = (f, arr) => arr.reduce((x, y) => [...x, ...f(y)], [])
flapMap? я хочу вирівняти свою карту, а не розмахувати її!
const flatMap = (arr, ...args) => [].concat(...arr.map(...args));(або використовувати, applyякщо ви не можете використовувати оператор поширення) - хоча ця версія concat має проблеми з розміром стека викликів для величезних масивів, як згадується в рішенні нижче
Я знаю, ви сказали, що не хочете визначати це самостійно, але ця реалізація є досить тривіальним визначенням.
Це також є з тієї ж сторінки github:
Ось трохи коротший спосіб використання es6-розширення, подібного до ренаудтретра - але використання es6 і не додавання до прототипу.
var flatMap = (a, cb) => [].concat(...a.map(cb))
const s = (v) => v.split(',')
const arr = ['cat,dog', 'fish,bird']
flatMap(arr, s)
Чи допомогло б щось із цього?
Слід зазначити (завдяки @ftor), що це останнє "рішення" страждає від "перевищено максимальний розмір стека викликів", якщо його викликати дійсно великим (наприклад, 300 тис. Елементів) масивом a.
[].concat(...(new Array(300000).fill("foo").map(x => x.toUpperCase()))). Звичайно, це кутова справа. Але вам слід хоча б згадати про це.
Lodash надає функцію плоскої карти, яка для мене практично еквівалентна Javascript, що забезпечує її безпосередньо. Якщо ви не користувач Lodash, то Array.reduce()метод ES6 може дати вам той самий результат, але вам потрібно зіставити, а потім зрівняти дискретними кроками.
Нижче наведено приклад кожного методу, що відображає список цілих чисел і повертає лише шанси.
Лодаш:
_.flatMap([1,2,3,4,5], i => i%2 !== 0 ? [i] : [])
ES6 Зменшення:
[1,2,3,4,5].map(i => i%2 !== 0 ? [i] : []).reduce( (a,b) => a.concat(b), [] )
Досить стислим підходом є використання Array#concat.apply:
const flatMap = (arr, f) => [].concat.apply([], arr.map(f))
console.log(flatMap([1, 2, 3], el => [el, el * el]));
Я зробив щось подібне:
Array.prototype.flatMap = function(selector){
return this.reduce((prev, next) =>
(/*first*/ selector(prev) || /*all after first*/ prev).concat(selector(next)))
}
[[1,2,3],[4,5,6],[7,8,9]].flatMap(i => i); //[1, 2, 3, 4, 5, 6, 7, 8, 9]
[{subarr:[1,2,3]},{subarr:[4,5,6]},{subarr:[7,8,9]}].flatMap(i => i.subarr); //[1, 2, 3, 4, 5, 6, 7, 8, 9]
Тепер у нас є flatMap()Javascript! І це підтримується досить добре
Метод flatMap () спочатку відображає кожен елемент за допомогою функції відображення, а потім згладжує результат у новий масив. Він ідентичний карті (), за якою слідує квартира () глибиною 1
const dublicate = x => [x, x];
console.log([1, 2, 3].flatMap(dublicate))
{ "message": "Uncaught TypeError: [1,2,3].flatMap is not a function", "filename": "https://stacksnippets.net/js", "lineno": 15, "colno": 23 }
Array.prototype.flatMap()зараз прибув до JS. Однак не всі браузери можуть підтримувати їх перевірку на поточну сумісність браузера з веб-документами Mozilla .
Те , що flatMap()метод робить спочатку відображає кожен елемент , використовуючи функцію зворотного виклику в якості аргументу, а потім згладжує результат в новий масив (2D - масив тепер 1d , так як елементи розплющені).
Ось також приклад використання функції:
let arr = [[2], [4], [6], [8]]
let newArr = arr.flatMap(x => [x * 2]);
console.log(newArr);
arr.reduce((arr, v) => (arr.push(...v), arr), [])?