首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >将可迭代的Javascript转换为数组

将可迭代的Javascript转换为数组
EN

Stack Overflow用户
提问于 2015-02-25 20:06:16
回答 8查看 98.7K关注 0票数 212

我正在尝试使用Javascript EC6的新Map对象,因为它已经在最新的火狐和Chrome版本中得到了支持。

但我发现它在“函数式”编程中非常有限,因为它缺乏经典的映射、过滤器等方法,这些方法可以很好地与[key, value]对一起工作。它有一个forEach,但不返回回调结果。

如果我可以将它的map.entries()从一个MapIterator转换成一个简单的数组,那么我就可以使用标准的.map.filter,而不需要额外的修改。

有没有一种“好”的方法将Javascript迭代器转换成数组?在python中,这和做list(iterator)一样简单……但是Array(m.entries())返回了一个以迭代器为第一个元素的数组!

编辑

我忘记说明我正在寻找一个在地图工作的地方都能工作的答案,这意味着至少是Chrome和火狐(Array.from不能在Chrome上工作)。

PS.

我知道有很棒的wu.js,但它对traceur的依赖让我很反感……

EN

回答 8

Stack Overflow用户

回答已采纳

发布于 2015-02-25 20:23:19

您正在寻找新的Array.from function,它可以将任意迭代器转换为数组实例:

代码语言:javascript
复制
var arr = Array.from(map.entries());

现在是supported in Edge, FF, Chrome and Node 4+

当然,直接在迭代器接口上定义mapfilter和类似的方法可能是值得的,这样就可以避免分配数组。您可能还希望使用生成器函数,而不是高阶函数:

代码语言:javascript
复制
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;
}
票数 301
EN

Stack Overflow用户

发布于 2015-02-25 21:00:25

[...map.entries()]Array.from(map.entries())

这非常简单。

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

票数 56
EN

Stack Overflow用户

发布于 2015-02-25 20:46:56

不需要将Map转换为Array。您可以简单地为Map对象创建mapfilter函数:

代码语言:javascript
复制
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 (即!字符)附加到其键为基元的映射的每个条目的值。

代码语言:javascript
复制
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";
}
代码语言:javascript
复制
<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.prototype上添加mapfilter方法,以使其读起来更好。尽管通常不建议修改本机原型,但我认为在Map.prototypemapfilter的情况下可能会有例外

代码语言:javascript
复制
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";
}
代码语言:javascript
复制
<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的回答中,他为所有可迭代对象创建了通用的mapfilter生成器函数。使用它们的好处是,因为它们是生成器函数,所以它们不会分配中间可迭代对象。

例如,上面定义的mapfilter函数创建新的Map对象。因此,调用object.filter(primitive).map(appendBang)会创建两个新的Map对象:

代码语言:javascript
复制
var intermediate = object.filter(primitive);
var result = intermediate.map(appendBang);

创建中间可迭代对象的开销很大。Bergi的生成器函数解决了这个问题。它们不分配中间对象,但允许一个迭代器懒惰地将其值提供给下一个迭代器。这种优化在函数式编程语言中称为fusion or deforestation,它可以显着提高程序性能。

我对Bergi的生成器函数唯一的问题是它们不是特定于Map对象的。相反,它们是针对所有可迭代对象的泛化。因此,它不是使用(value, key)对调用回调函数(正如我在Map上映射时所期望的那样),而是使用(value, index)对调用回调函数。否则,这是一个很好的解决方案,我肯定会推荐使用它,而不是我提供的解决方案。

下面是我用来映射和过滤Map对象的特定生成器函数:

代码语言:javascript
复制
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;
}

它们的用法如下:

代码语言:javascript
复制
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";
}
代码语言:javascript
复制
<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>

如果你想要一个更流畅的界面,你可以这样做:

代码语言:javascript
复制
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";
}
代码语言:javascript
复制
<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>

希望这能有所帮助。

票数 19
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/28718641

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档