JavaScript에서 세트를 매핑 / 축소 / 필터링하는 방법?


131

JavaScript에서 map/ reduce/ filter/ etc를하는 방법이 Set있습니까? 아니면 내 자신을 작성해야합니까?

합리적인 Set.prototype확장 기능은 다음과 같습니다.

Set.prototype.map = function map(f) {
  var newSet = new Set();
  for (var v of this.values()) newSet.add(f(v));
  return newSet;
};

Set.prototype.reduce = function(f,initial) {
  var result = initial;
  for (var v of this) result = f(result, v);
  return result;
};

Set.prototype.filter = function filter(f) {
  var newSet = new Set();
  for (var v of this) if(f(v)) newSet.add(v);
  return newSet;
};

Set.prototype.every = function every(f) {
  for (var v of this) if (!f(v)) return false;
  return true;
};

Set.prototype.some = function some(f) {
  for (var v of this) if (f(v)) return true;
  return false;
};

조금만 설정합시다

let s = new Set([1,2,3,4]);

그리고 어리석은 작은 기능들

const times10 = x => x * 10;
const add = (x,y) => x + y;
const even = x => x % 2 === 0;

그리고 그들이 어떻게 작동하는지보십시오

s.map(times10);    //=> Set {10,20,30,40}
s.reduce(add, 0);  //=> 10
s.filter(even);    //=> Set {2,4}
s.every(even);     //=> false
s.some(even);      //=> true

멋지지 않습니까? 그래, 나도 그렇게 생각해 그것을 추악한 반복자 사용법과 비교하십시오.

// puke
let newSet = new Set();
for (let v in s) {
  newSet.add(times10(v));
}

// barf
let sum = 0;
for (let v in s) {
  sum = sum + v;
}

JavaScript 로 달성 map하고 reduce사용하는 더 좋은 방법이 Set있습니까?


map-reduce-ing a의 Set문제점은 Sets가 Functors가 아니라는 것입니다.
Bartek Banachewicz

@BartekBanachewicz 그래 그게 문제 야 ... 맞아?
감사합니다.

2
글쎄요 var s = new Set([1,2,3,4]); s.map((a) => 42);. map일반적으로 필요하지 않은 요소 수를 변경합니다 . 유지되는 객체의 일부만 비교하는 경우 더 나빠질 수 있습니다. 기술적으로 얻을 수있는 것은 지정되어 있지 않기 때문입니다.
Bartek Banachewicz

나는 그것을 고려했지만, 개인적으로 내가 그것을 무효라고 생각하지는 않습니다. forEach그래도 적어도 그 시나리오에는 존재하지만 왜 그렇지 reduce않습니까?
감사합니다.

답변:


105

이를 수행하는 간단한 방법은 ES6 스프레드 연산자를 통해 배열로 변환하는 것입니다.

그런 다음 모든 어레이 기능을 사용할 수 있습니다.

const mySet = new Set([1,2,3,4]);
[...mySet].reduce()

1
이 기능은 Set에서 사용할 수 없기 때문에! 이 주제에는 아직 존재하지 않는 완전하고 안내되며 이해되는 해결 방법입니다. '시간이 더 오래 걸린다'는 사실은 Set이 이러한 기능을 구현할 때까지 해결 비용을 지불하는 슬픈 가격입니다!
ZephDavies

1
이것과 Array.from의 차이점
pete

9
나를 위해 적어도,이 사이의 차이는 Array.fromArray.from타이프 라이터와 함께 작동합니다. 를 사용 [...mySet]하면 오류가 발생합니다 :TS2461: Type 'Set<number>' is not an array type.
Mikal Madsen

1
spread vs Array.from ()에 대해서는 stackoverflow.com/a/40549565/5516454를 참조 하십시오. 기본적으로 둘 다 여기에서 사용할 수 있습니다. Array.from ()은 @@iterator메소드를 구현하지 않는 배열과 유사한 객체를 추가로 수행 할 수 있습니다 .
ZephDavies

여전히 typescript로 작동하지 않습니다. 나는 얻는다ERROR TypeError: this.sausages.slice is not a function
Simon_Weaver

22

의견의 논의를 요약하면 :에 세트에 대한 기술적 이유가없는 동안 하지 가지고 reduce, 그것은 현재 제공되지 그리고 우리는 단지 그것을 ES7의 변화를 기대 할 수 있습니다.

에 관해서는 map그것을 단독으로 호출하면 Set제약 조건을 위반 할 수 있으므로 여기에서의 존재는 논란의 여지가 있습니다.

함수를 사용하여 매핑을 고려하십시오 (a) => 42-세트의 크기를 1로 변경하며, 이것이 원하는 것일 수도 아닐 수도 있습니다 .

어쨌든 배거야 예를 들어 있기 때문에, 당신이 적용 할 수있는 위반 나왔습니다 확인 당신이 만약 map단지로 전달하기 전에 모든 요소에 대한 부분을 reduce수용하여, 그 중간 (컬렉션 이 시점에서 설정되어 있지 않은 )의 그 축소 될 요소가 중복되었을 수 있습니다. 이것은 본질적으로 처리를 수행하기 위해 Array로 변환하는 것과 같습니다.


1
이것은 (위의 코드를 사용하여)을 제외하고, 대부분 잘 s.map(a => 42)발생합니다 Set { 42 }요소 "중복"매핑 결과가 서로 다른 길이를 할 수 있도록하지만,이되지 않습니다. 어쩌면 문구를 업데이트하고이 답변을 수락하겠습니다.
감사합니다.

@naomik Oh derp 글을 쓸 때 첫 커피를 마쳤습니다. 두 번째로, 축소하기 위해 전달 된 중간 컬렉션 은 세트가 아니라면 즉시 요소를 가질 수 있습니다 .
Bartek Banachewicz

오 알 겠어-지도가 동일한 유형에 매핑되어야하므로 대상 세트에서 충돌이 발생할 수 있습니다. 이 질문을 발견했을 때 map이 세트의 배열에 매핑 될 것이라고 생각했습니다. (set.toArray (). map ()`한 것처럼
Simon_Weaver 5

2
Scala와 Haskell에서 세트는 맵 작업을 지원합니다. 세트의 요소 수를 줄일 수 있습니다.
Velizar Hristov

8

map/ reduce/ filteron Map/ Set컬렉션 이없는 원인은 주로 개념적인 문제인 것 같습니다. 자바 스크립트의 각 컬렉션 유형은 실제로이를 허용하기 위해 자체 반복 메소드를 지정해야합니다

const mySet = new Set([1,2,3]);
const myMap = new Map([[1,1],[2,2],[3,3]]);

mySet.map(x => x + 1);
myMap.map(([k, x]) => [k, x + 1]);

대신에

new Set(Array.from(mySet.values(), x => x + 1));
new Map(Array.from(myMap.entries(), ([k, x]) => [k, x + 1]));

대안은 entries/ values/ keysreturn 이기 때문에 iterable / iterator 프로토콜의 일부로 map / reduce / filter를 지정하는 것 Iterator입니다. 모든 iterable이 "mappable"인 것은 아니지만 가능합니다. 또 다른 대안은이 목적을 위해 별도의 "수집 프로토콜"을 지정하는 것이 었습니다.

그러나 ES 에서이 주제에 대한 현재 토론을 모르겠습니다.

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