将Javascript迭代器转换为数组

2020/10/23 03:02 · javascript ·  · 0评论

我正在尝试使用Javascript EC6中的新Map对象,因为最新的Firefox和Chrome版本已支持该对象。

但是我发现它在“功能性”编程中非常受限制,因为它缺少经典的map,filter等方法,可以很好地与一[key, value]配合使用它有一个forEach,但是不返回回调结果。

如果我可以将其map.entries()从MapIterator转换为简单的Array,则可以使用standard .map.filter而无需进行其他操作。

有没有一种“好的”方法可以将Javascript迭代器转换为数组?在python中,这很容易list(iterator)...但是Array(m.entries())返回一个以Iterator作为其第一个元素的数组!

编辑

我忘记指定要寻找的答案,无论Map在哪里工作,它都适用,这意味着至少Chrome和Firefox(Array.from在Chrome中不起作用)。

PS。

我知道这里有一个很棒的wu.js,但是它对traceur的依赖使我失望...

您正在寻找将任意可迭代对象转换为数组实例的新Array.from函数

var arr = Array.from(map.entries());

Edge,FF,Chrome和Node 4+现在支持该功能

当然,它可能是值得来定义mapfilter并直接迭代器界面上类似的方法,这样就可以避开分配阵列。您可能还想使用生成器函数而不是高阶函数:

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())

超级容易。

无论如何-迭代器缺少reduce,filter和类似的方法。您必须自己编写它们,因为它比将Map转换为数组然后返回的性能更高。但是不要跳Map-> Array-> Map-> Array-> Map-> Array,因为这会降低性能。

无需将转换MapArray你可以简单地创建mapfilter用于功能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>

您还可以添加mapfilter方法,Map.prototype以使其阅读效果更好。尽管通常不建议以修改本机的原型但我认为,一个例外可能的情况下进行map,并filterMap.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>

编辑:在贝尔吉的答案中,他为所有可迭代对象创建了泛型函数mapfilter生成器函数。使用它们的好处是,由于它们是生成器函数,因此它们不分配中间的可迭代对象。

例如,上面定义的mymapfilter函数创建新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 => {...});

您可以使用类似于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();
本文地址:http://javascript.askforanswer.com/jiangjavascriptdiedaiqizhuanhuanweishuzu.html
文章标签: ,  
版权声明:本文为原创文章,版权归 javascript 所有,欢迎分享本文,转载请保留出处!

文件下载

老薛主机终身7折优惠码boke112

上一篇:
下一篇:

评论已关闭!