최신 Firefox 및 Chrome 버전에서 이미 지원되므로 Javascript EC6 의 새 Map 객체 를 사용하려고합니다 .
그러나 고전적인 맵, 필터 등 [key, value]
쌍이 잘 작동하는 메소드가 없기 때문에 “기능”프로그래밍에서는 매우 제한적입니다 . forEach가 있지만 콜백 결과를 리턴하지 않습니다.
나는 그것의 변환 수 있다면 map.entries()
간단한 배열로 MapIterator에서 나는 다음 표준을 사용할 수 .map
, .filter
추가 해킹으로.
Javascript Iterator를 Array로 변환하는 “좋은”방법이 있습니까? 파이썬에서는 그렇게하는 list(iterator)
것이 쉽지만 … Array(m.entries())
Iterator를 첫 번째 요소로 사용하여 배열을 반환하십시오!
편집하다
지도가 작동하는 곳에서 작동하는 답변을 찾고 있음을 지정하는 것을 잊었습니다. 최소한 Chrome 및 Firefox를 의미합니다 (Array.from은 Chrome에서 작동하지 않음).
추신.
환상적인 wu.js 가 있다는 것을 알고 있지만 traceur에 대한 의존성은 나를 미치게 합니다 …
답변
임의의 이터 러블을 배열 인스턴스로 변환 하는 새로운 Array.from
함수 를 찾고 있습니다 .
var arr = Array.from(map.entries());
이제 Edge, FF, Chrome 및 Node 4+에서 지원됩니다 .
물론, 정의 할 가치가있을 수도 있습니다 map
, filter
당신은 배열을 할당 피할 수 그래서, 직접 반복자 인터페이스에 유사한 방법. 고차 함수 대신 생성기 함수를 사용할 수도 있습니다.
function* map(iterable) {
var i = 0;
for (var item of iterable)
yield yourTransformation(item, i++);
}
function* filter(iterable) {
var i = 0;
for (var item of iterable)
if (yourPredicate(item, i++))
yield item;
}
답변
[...map.entries()]
또는 Array.from(map.entries())
매우 쉽습니다.
어쨌든 반복자에는 감소, 필터링 및 유사한 방법이 부족합니다. Map을 배열로 변환하는 것보다 성능이 우수하므로 직접 작성해야합니다. 그러나 Map-> Array-> Map-> Array-> Map-> Array로 점프하지 마십시오. 성능이 저하 될 수 있습니다.
답변
을 변환 할 필요가 없습니다 Map
으로는 Array
. 당신은 간단하게 만들 수 map
및 filter
대한 기능을 Map
제품 :
function map(functor, object, self) {
var result = new Map;
object.forEach(function (value, key, object) {
result.set(key, functor.call(this, value, key, object));
}, self);
return result;
}
function filter(predicate, object, self) {
var result = new Map;
object.forEach(function (value, key, object) {
if (predicate.call(this, value, key, object)) result.set(key, value);
}, self);
return result;
}
예를 들어 !
키가 기본 요소 인 맵의 각 항목 값에 뱅 (예 : 문자)을 추가 할 수 있습니다.
var object = new Map;
object.set("", "empty string");
object.set(0, "number zero");
object.set(object, "itself");
var result = map(appendBang, filter(primitive, object));
alert(result.get("")); // empty string!
alert(result.get(0)); // number zero!
alert(result.get(object)); // undefined
function primitive(value, key) {
return isPrimitive(key);
}
function appendBang(value) {
return value + "!";
}
function isPrimitive(value) {
var type = typeof value;
return value === null ||
type !== "object" &&
type !== "function";
}
<script>
function map(functor, object, self) {
var result = new Map;
object.forEach(function (value, key, object) {
result.set(key, functor.call(this, value, key, object));
}, self || null);
return result;
}
function filter(predicate, object, self) {
var result = new Map;
object.forEach(function (value, key, object) {
if (predicate.call(this, value, key, object)) result.set(key, value);
}, self || null);
return result;
}
</script>
당신은 또한 추가 할 수 있습니다 map
와 filter
의 방법은 Map.prototype
더 나은 읽을 수 있도록. 일반적으로 아직 기본 프로토 타입을 수정하는 것이 좋습니다되지는 않지만 나는 예외의 경우에 할 수 있다고 생각 map
하고 filter
대한 Map.prototype
:
var object = new Map;
object.set("", "empty string");
object.set(0, "number zero");
object.set(object, "itself");
var result = object.filter(primitive).map(appendBang);
alert(result.get("")); // empty string!
alert(result.get(0)); // number zero!
alert(result.get(object)); // undefined
function primitive(value, key) {
return isPrimitive(key);
}
function appendBang(value) {
return value + "!";
}
function isPrimitive(value) {
var type = typeof value;
return value === null ||
type !== "object" &&
type !== "function";
}
<script>
Map.prototype.map = function (functor, self) {
var result = new Map;
this.forEach(function (value, key, object) {
result.set(key, functor.call(this, value, key, object));
}, self || null);
return result;
};
Map.prototype.filter = function (predicate, self) {
var result = new Map;
this.forEach(function (value, key, object) {
if (predicate.call(this, value, key, object)) result.set(key, value);
}, self || null);
return result;
};
</script>
편집 : Bergi의 대답에서 그는 모든 반복 가능한 객체에 대해 일반 map
및 filter
생성기 함수를 만들었습니다 . 그것들을 사용하는 장점은 생성기 함수이므로 중간 반복 가능 객체를 할당하지 않는다는 것입니다.
예를 들어, 위에서 정의한 my map
및 filter
함수는 새 Map
객체를 만듭니다 . 따라서 호출 object.filter(primitive).map(appendBang)
하면 두 개의 새로운 Map
객체 가 생성 됩니다.
var intermediate = object.filter(primitive);
var result = intermediate.map(appendBang);
반복 가능한 중간 객체를 만드는 것은 비용이 많이 듭니다. Bergi의 발전기 기능이이 문제를 해결합니다. 중간 객체를 할당하지 않지만 하나의 반복자가 값을 느리게 다음 값으로 공급할 수 있습니다. 이러한 종류의 최적화는 기능적 프로그래밍 언어에서 융합 또는 삼림 벌채 로 알려져 있으며 프로그램 성능을 크게 향상시킬 수 있습니다.
Bergi의 생성기 기능에서 내가 가진 유일한 문제는 그것들이 Map
객체에 국한되지 않는다는 것 입니다. 대신, 반복 가능한 모든 객체에 대해 일반화됩니다. 따라서 (value, key)
쌍으로 콜백 함수를 호출하는 대신 (을 통해 매핑 할 때 예상 되는대로 Map
) (value, index)
쌍으로 콜백 함수를 호출합니다 . 그렇지 않으면 훌륭한 솔루션이므로 제공된 솔루션보다 확실히 사용하는 것이 좋습니다.
따라서 이들은 Map
객체 매핑 및 필터링에 사용할 특정 생성기 함수입니다 .
function * map(functor, entries, self) {
var that = self || null;
for (var entry of entries) {
var key = entry[0];
var value = entry[1];
yield [key, functor.call(that, value, key, entries)];
}
}
function * filter(predicate, entries, self) {
var that = self || null;
for (var entry of entries) {
var key = entry[0];
var value = entry[1];
if (predicate.call(that, value, key, entries)) yield [key, value];
}
}
function toMap(entries) {
var result = new Map;
for (var entry of entries) {
var key = entry[0];
var value = entry[1];
result.set(key, value);
}
return result;
}
function toArray(entries) {
var array = [];
for (var entry of entries) {
array.push(entry[1]);
}
return array;
}
다음과 같이 사용할 수 있습니다.
var object = new Map;
object.set("", "empty string");
object.set(0, "number zero");
object.set(object, "itself");
var result = toMap(map(appendBang, filter(primitive, object.entries())));
alert(result.get("")); // empty string!
alert(result.get(0)); // number zero!
alert(result.get(object)); // undefined
var array = toArray(map(appendBang, filter(primitive, object.entries())));
alert(JSON.stringify(array, null, 4));
function primitive(value, key) {
return isPrimitive(key);
}
function appendBang(value) {
return value + "!";
}
function isPrimitive(value) {
var type = typeof value;
return value === null ||
type !== "object" &&
type !== "function";
}
<script>
function * map(functor, entries, self) {
var that = self || null;
for (var entry of entries) {
var key = entry[0];
var value = entry[1];
yield [key, functor.call(that, value, key, entries)];
}
}
function * filter(predicate, entries, self) {
var that = self || null;
for (var entry of entries) {
var key = entry[0];
var value = entry[1];
if (predicate.call(that, value, key, entries)) yield [key, value];
}
}
function toMap(entries) {
var result = new Map;
for (var entry of entries) {
var key = entry[0];
var value = entry[1];
result.set(key, value);
}
return result;
}
function toArray(entries) {
var array = [];
for (var entry of entries) {
array.push(entry[1]);
}
return array;
}
</script>
보다 유창한 인터페이스를 원한다면 다음과 같이 할 수 있습니다.
var object = new Map;
object.set("", "empty string");
object.set(0, "number zero");
object.set(object, "itself");
var result = new MapEntries(object).filter(primitive).map(appendBang).toMap();
alert(result.get("")); // empty string!
alert(result.get(0)); // number zero!
alert(result.get(object)); // undefined
var array = new MapEntries(object).filter(primitive).map(appendBang).toArray();
alert(JSON.stringify(array, null, 4));
function primitive(value, key) {
return isPrimitive(key);
}
function appendBang(value) {
return value + "!";
}
function isPrimitive(value) {
var type = typeof value;
return value === null ||
type !== "object" &&
type !== "function";
}
<script>
MapEntries.prototype = {
constructor: MapEntries,
map: function (functor, self) {
return new MapEntries(map(functor, this.entries, self), true);
},
filter: function (predicate, self) {
return new MapEntries(filter(predicate, this.entries, self), true);
},
toMap: function () {
return toMap(this.entries);
},
toArray: function () {
return toArray(this.entries);
}
};
function MapEntries(map, entries) {
this.entries = entries ? map : map.entries();
}
function * map(functor, entries, self) {
var that = self || null;
for (var entry of entries) {
var key = entry[0];
var value = entry[1];
yield [key, functor.call(that, value, key, entries)];
}
}
function * filter(predicate, entries, self) {
var that = self || null;
for (var entry of entries) {
var key = entry[0];
var value = entry[1];
if (predicate.call(that, value, key, entries)) yield [key, value];
}
}
function toMap(entries) {
var result = new Map;
for (var entry of entries) {
var key = entry[0];
var value = entry[1];
result.set(key, value);
}
return result;
}
function toArray(entries) {
var array = [];
for (var entry of entries) {
array.push(entry[1]);
}
return array;
}
</script>
희망이 도움이됩니다.
답변
2019 년의 작은 업데이트 :
이제 Array.from은 보편적으로 사용 가능한 것으로 보이며 더 나아가 두 번째 인수 mapFn을 허용 하므로 중간 배열을 만들 수 없습니다. 이것은 기본적으로 다음과 같습니다
Array.from(myMap.entries(), entry => {...});
답변
iterables에 대해 배열과 유사한 메소드를 구현하는 https://www.npmjs.com/package/itiriri 와 같은 라이브러리를 사용할 수 있습니다 .
import { query } from 'itiriri';
const map = new Map();
map.set(1, 'Alice');
map.set(2, 'Bob');
const result = query(map)
.filter([k, v] => v.indexOf('A') >= 0)
.map([k, v] => `k - ${v.toUpperCase()}`);
for (const r of result) {
console.log(r); // prints: 1 - ALICE
}
답변
배열 배열 (키 및 값)을 얻을 수 있습니다 .
[...this.state.selected.entries()]
/**
*(2) [Array(2), Array(2)]
*0: (2) [2, true]
*1: (2) [3, true]
*length: 2
*/
그런 다음지도 반복자가있는 키와 같이 내부에서 값을 쉽게 얻을 수 있습니다.
[...this.state.selected[asd].entries()].map(e=>e[0])
//(2) [2, 3]
답변
fluent-iterable 을 사용 하여 배열로 변환 할 수도 있습니다 .
const iterable: Iterable<T> = ...;
const arr: T[] = fluent(iterable).toArray();