Преобразование итератора Javascript в массив
Я пытаюсь использовать новый объект Map из Javascript EC6, поскольку он уже поддерживается в последних версиях Firefox и Chrome.
Но я нахожу его очень ограниченным в "функциональном" программировании, потому что ему не хватает классических карт, фильтров и т.д. методов, которые бы хорошо работали с парой [key, value]
. Он имеет значение forEach, но не возвращает результат обратного вызова.
Если бы я мог преобразовать его map.entries()
из MapIterator в простой массив, тогда я мог бы использовать стандартные .map
, .filter
без дополнительных хаков.
Есть ли "хороший" способ превратить Итератор Javascript в массив?
В python это так же просто, как сделать list(iterator)
... но Array(m.entries())
вернуть массив с Iterator в качестве его первого элемента!!!
ИЗМЕНИТЬ
Я забыл указать, что я ищу ответ, который работает везде, где работает Map, что означает, по крайней мере, Chrome и Firefox (Array.from не работает в Chrome).
PS.
Я знаю там фантастический wu.js, но его зависимость от traceur меня отталкивает...
Ответы
Ответ 1
Вы ищете новую функцию 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;
}
Ответ 2
[...map.entries()]
или Array.from(map.entries())
Это супер-просто.
В любом случае - итераторам не хватает средств, фильтров и подобных методов. Вы должны написать их самостоятельно, так как это более перформативно, чем преобразование карты в массив и обратно. Но не делайте переходов Map → Array → Map → Array → Map → Array, потому что это убьет производительность.
Ответ 3
Нет необходимости преобразовывать 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;
}
Например, вы можете добавить символ bang (т.е. !
) к значению каждой записи карты, чей ключ является примитивным.
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>
Ответ 4
Небольшое обновление с 2019 года:
Теперь Array.from представляется универсально доступным, и, кроме того, он принимает второй аргумент mapFn, который не позволяет ему создавать промежуточный массив. В основном это выглядит так:
Array.from(myMap.entries(), entry => {...});
Ответ 5
Вы можете использовать библиотеку, такую как 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
}
Ответ 6
Вы можете получить массив массивов (ключ и значение):
[...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]