자바 스크립트에 Array.prototype.flatMap이없는 이유는 무엇입니까?


82

flatMap컬렉션에서 매우 유용하지만 javascript는 Array.prototype.map. 왜?

수동으로 flatMap정의하지 않고도 쉽고 효율적인 방법으로 자바 스크립트에서 에뮬레이션하는 방법이 flatMap있습니까?


10
"왜?" 아직 아무도 제안하지 않았기 때문에? 새로운 기능을 제안하는 방법은 다음과 같습니다 . "flatMap을 에뮬레이션 할 수있는 방법이 있습니까? flatMap을 수동으로 정의하지 않고 ..." 어? 이해가 안 돼요. 당신은 arr.reduce((arr, v) => (arr.push(...v), arr), [])?
Felix Kling 2016 년

(^ 그것은 평평한 부분 일뿐이므로 arr.map(...).reduce(...)).
Felix Kling 2016 년

ping 후 어레이를 평평하게 만들 수 있습니다 .map.
kennytm

1
흠, "에뮬레이트"하고 싶지만 "정의"하지는 않습니다. 그게 무슨 뜻일까요?

8
곧 JS의 일부가 될 것입니다. tc39.github.io/proposal-flatMap
Vijaiendran

답변:


99

업데이트 : 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 ]


자바 스크립트에 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; }


1
프로토 타입에 대한 추가 사항 (예 Array.prototype._mylib_flatMap:) 에 네임 스페이스를 지정하는 것이 더 나은 것으로 간주 되거나 단순히를 정의하는 대신 ES6 기호를 사용하는 것이 더 좋습니다 Array.prototype.flatMap.
Fengyang Wang

11
@FengyangWang "더 나은 것으로 간주" 는 매우 주관적입니다. 이것이 당신의 앱이고 프로토 타입을 확장 할 이유가 있다면, 그것에 문제가 없습니다. 타인의 사용을 위해 배포하는 것이 라이브러리 / 모듈 / 프레임 워크라면 동의합니다. 그러나 의견은이 문제를 논의 할 수있는 장소가 아닙니다.이 문제는 의견에 제공되어야하는 것보다 더 많은 설명과 세부 사항이 필요합니다.
당신을 감사

첫 번째는 추악합니다. 함수로 정의 된 flatMap은 코드를 엉망으로 만들 것입니다 map. 전역 함수 로 정의 된 함수 코드를 상상해보세요 ! 두 번째는 나쁜 관행입니다
세르게이 Alaev

3
@SergeyAlaev re : "전역 함수로 맵을 상상해보세요 . " haha 많은 유틸리티 함수에서 정확히 그렇게합니다. 나는 화살표 기능의 시퀀스를 사용하여 그들을 카레도합니다. "미운"은 주관적입니다. 그리고 당신은 당신의 "나쁜 관행"코멘트를 뒷받침 할 논쟁을하지 않았습니다. 당신의 말은 당신이 함수형 프로그래밍에 대한 경험이 거의 없다는 것을 나타냅니다. 전주곡에 "글로벌"의 더미가 포함 된 Haskell과 같은 언어를 예로 들어 보겠습니다. 당신은 그것에 익숙하지 않습니다.
당신을 감사

5
이 @SergeyAlaev 또는 고려 라켓 append, map, filter, foldl, foldr디폴트의 이름 공간에서 수많은 다른 사람의 사이에서. 누군가 "글로벌이 나쁘다"또는 "네이티브를 확장하는 것은 나쁘다"라고 말하는 것을 들었 기 때문에 나쁜 습관이 아닙니다. 라켓은 가장 잘 설계된 언어 중 하나입니다. 당신은 그것을 적절하게 어떻게 / 언제 해야할지 모릅니다.
당신을 감사

48

flatMapES2019 (ES10)의 일부로 TC39의 승인을 받았습니다. 다음과 같이 사용할 수 있습니다.

[1, 3].flatMap(x => [x, x + 1]) // > [1, 2, 3, 4]

다음은 메서드의 내 고유 구현입니다.

const flatMap = (f, arr) => arr.reduce((x, y) => [...x, ...f(y)], [])

flatMap의 MDN 기사


특히, flapMap는 MDN에 따라 노드 11.0.0에서 공식적으로 : developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/...
칼 월시

3
@CarlWalsh 죄송합니다, 저항 할 수 없습니다. 도대체 무엇입니까 flapMap? 나는 내지도를 평평하게 만들고 싶다.
ErikE

또 다른 주제에서이 마침내 모나드로 자바 스크립트 배열의 변 ™ ️ 🙃
Kutyel

이것은 오래된 대답이지만 특히 큰 배열에서 매우 비효율적입니다 (새 배열을 만들고 각 반복에서 모든 이전 요소를 복사합니다). 또 다른 접근 방식은 concat을 사용하는 것입니다 const flatMap = (arr, ...args) => [].concat(...arr.map(...args));(또는 apply스프레드 연산자를 사용할 수없는 경우 사용)-이 concat 버전에는 솔루션 하위에 언급 된대로 거대한 배열에 대한 호출 스택 크기 문제가 있지만
Bali Balo

10

직접 정의하고 싶지 않다고 말씀 하셨지만 이 구현 은 매우 사소한 정의입니다.

동일한 github 페이지에도 다음이 있습니다.

다음은 renaudtertrais와 비슷하지만 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 덕분에)이 후자의 "솔루션"은 정말 큰 (예 : 300k 요소) 배열에서 호출 될 경우 "최대 호출 스택 크기 초과"문제가 발생한다는 점에 유의해야합니다 a.


2
이 구현은 대형 어레이의 스택을 날려 버릴 수 있습니다.

명확하게 말하면, @ftor, 당신은 내가 준 링크의 재귀 구현에 대해 이야기하고 있습니다.
Alan Mimms 2016 년

2
시도해보십시오 [].concat(...(new Array(300000).fill("foo").map(x => x.toUpperCase()))). 물론입니다. 코너 케이스입니다. 하지만 적어도 언급해야합니다.

감사. 이 효과에 메모를 추가했습니다.
Alan Mimms

7

Lodash 는 플랫 맵 기능을 제공하는데, 나에게는 자바 스크립트가 기본적으로 제공하는 것과 거의 동일합니다. Lodash 사용자가 아니라면 ES6의 Array.reduce()방법이 동일한 결과를 제공 할 수 있지만 별도의 단계로 매핑 한 다음 평면화해야합니다.

다음은 정수 목록을 매핑하고 배당률 만 반환하는 각 방법의 예입니다.

Lodash :

_.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), [] )

4

상당히 간결한 접근 방식 중 하나는 다음을 사용하는 것입니다 Array#concat.apply.

const flatMap = (arr, f) => [].concat.apply([], arr.map(f))

console.log(flatMap([1, 2, 3], el => [el, el * el]));


1

나는 다음과 같은 일을했다.

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]


안녕하세요 serhii, 부모가 하나의 개체 만 예기치 않은 결과를 제공 할 때이 코드를 시도했습니다. ```Array.prototype.flatMap = function (selector) {if (this.length == 1) {return selector (this [0]); } return this.reduce ((prev, next) => (/ * first * / selector (prev) || / * all after first * / prev) .concat (selector (next)))}; ```
Johnny

0

이제 flatMap()Javascript가 있습니다! 그리고 그것은 꽤 잘 지원됩니다

flatMap () 메서드는 먼저 매핑 함수를 사용하여 각 요소를 매핑 한 다음 결과를 새 배열로 평면화합니다. map () 뒤에 깊이 1의 flat ()이 오는 것과 동일합니다.

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 }
SolutionMill

어떤 Broser를 사용하고 있습니까? Edge, IE 및 Samsung Internet은 아직 지원하지 않습니다. Edge는 곧 V8에서 실행됩니다. 사람들을 지원하기 위해 그래서, 당신은 polyfil 사용할 수 있습니다
BIGINT

Chrome 버전 67.0.3396.87 (공식 빌드) (64 비트)
SolutionMill

브라우저가 오래되었습니다. 브라우저를 업데이트하거나 자동으로 업데이트되도록 설정해야합니다.
bigInt

0

Array.prototype.flatMap()이제 JS에 도착했습니다. 그러나 모든 브라우저가 Mozilla 웹 문서 에서 현재 브라우저 호환성을 확인하는 것을 지원하는 것은 아닙니다 .

어떤 flatMap()방법을 수행하는 첫 번째 후 새로운 배열 결과 (요소가 평평하게되기 때문에, 2 차원 배열되어 이제도 1d) 병합, 인수 콜백 함수를 사용하여 각 원소를 매핑한다.

다음은 함수 사용 방법의 예입니다.

let arr = [[2], [4], [6], [8]]

let newArr = arr.flatMap(x => [x * 2]);

console.log(newArr);

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.