Преобразование итератора 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]