如何减少链接映射时的迭代减少过滤器? [英] How to reduce iterations when chaining map reduce filter?

查看:103
本文介绍了如何减少链接映射时的迭代减少过滤器?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我一直在阅读关于 map reduce 过滤器

  let myArr = [1,2,3,4,5,6,7,8, 9] 
let sumOfDoubleOfOddNumbers = myArr.filter(num => num%2)
.map(num => num * 2)
.reduce((acc,currVal)=> ; acc + currVal,0);

运行3个不同的循环。

我也读过关于Java 8流的知识,并且知道它们使用了所谓的monad,也就是说,计算首先被存储。它们只在一次迭代中执行一次。例如,

  Stream.of(d2,a2,b1,b3,c )
.map(s - > {
System.out.println(map:+ s);
return s.toUpperCase();
})
.filter(s - > {
System.out.println(filter:+ s);
return s.startsWith(A);
})
.forEach(s - > System.out.println(forEach:+ s));

//映射:d2
//过滤器:D2
//映射:a2
//过滤器:A2
// forEach:A2
// map:b1
//过滤器:B1
//地图:b3
//过滤器:B3
//地图:c
//过滤器:C

PS:Java代码取自: http://winterbe.com/posts/2014/07/31/java8-stream-tutorial-examples /



还有很多其他语言使用相同的方法。有没有办法在JS中以相同的方式来做到这一点?

解决方案

这是Java代码的精确克隆。与Bergi的解决方案不同,不需要修改全局原型。

class stream {constructor (iter){this.iter = iter; } * [Symbol.iterator](){yield * this.iter; }(... args){return new this(function *(){yield * args}()); } _chain(next){return new this.constructor(next.call(this)); } map(fn){return this._chain(function *(){for(let a of this)yield fn(a);}); (fn){return this._chain(function *(){for(let a of this)if(fn(a))yield(a);}); (for aach(fn){for(let a of this)fn(a)}} Stream.of(d2,a2,b1,b3,c).map(s => {console.log(map:+ s); return s.toUpperCase();}).filter(s => {console.log(filter:+ s); return s.startsWith(A );}).forEach(s => console.log('forEach',s));



实际上,链接功能可以与特定的迭代器分离,以提供一个通用框架:

  // polyfill,稍后在
中删除我Array.prototype.values = Array.prototype.values ||函数*(){yield * this};

class Iter {
构造函数(iter){this.iter = iter}
* [Symbol.iterator](){yield * this.iter}
static (... args){返回this.from(args)}
static(from args){return new this(args.values())}
_(gen){return new this。构造函数(gen.call(this))}
}

现在,例如:

  let map = fn =>函数*(){
(让这个)
产生fn(a);
};

let filter = fn =>函数*(){
(让这个)
if(fn(a))
yield(a);
};

it = Iter.of(d2,a2,b1,b3,c,a000)
._(地图(s => ; s.toUpperCase()))
._(filter(s => s.startsWith(A)))
._(function *(){
for x [... this] .sort())
yield x;
});

console.log([... it])


I have been reading about map, reduce and filter a lot because of how much they are used in react and FP in general. If we write something like:

let myArr = [1,2,3,4,5,6,7,8,9]
let sumOfDoubleOfOddNumbers = myArr.filter(num => num % 2)
                                   .map(num => num * 2)
                                   .reduce((acc, currVal) => acc + currVal, 0);

3 different loops are run.

I've read about Java 8 streams as well and know that they use what is called a monad, ie, the computations are stored first. They are performed once only in one iteration. For example,

Stream.of("d2", "a2", "b1", "b3", "c")
    .map(s -> {
        System.out.println("map: " + s);
        return s.toUpperCase();
    })
    .filter(s -> {
        System.out.println("filter: " + s);
        return s.startsWith("A");
    })
    .forEach(s -> System.out.println("forEach: " + s));

// map:     d2
// filter:  D2
// map:     a2
// filter:  A2
// forEach: A2
// map:     b1
// filter:  B1
// map:     b3
// filter:  B3
// map:     c
// filter:  C

PS: Java code is taken from: http://winterbe.com/posts/2014/07/31/java8-stream-tutorial-examples/

There are many other languages that use this same method. Is there a way to do it the same way in JS as well?

解决方案

This is an exact clone of your Java code. Unlike Bergi's solution, no need to modify global prototypes.

class Stream {
    constructor(iter) {
        this.iter = iter;
    }

    * [Symbol.iterator]() {
        yield* this.iter;
    }

    static of(...args) {
        return new this(function* () {
            yield* args
        }());
    }

    _chain(next) {
        return new this.constructor(next.call(this));
    }

    map(fn) {
        return this._chain(function* () {
            for (let a of this)
                yield fn(a);
        });
    }

    filter(fn) {
        return this._chain(function* () {
            for (let a of this)
                if (fn(a))
                    yield (a);
        });
    }

    forEach(fn) {
        for (let a of this)
            fn(a)
    }
}


Stream.of("d2", "a2", "b1", "b3", "c")
    .map(s => {
        console.log("map: " + s);
        return s.toUpperCase();
    })
    .filter(s => {
        console.log("filter: " + s);
        return s.startsWith("A");
    })
    .forEach(s => console.log('forEach', s));

Actually, the chaining functionality could be decoupled from specific iterators to provide a generic framework:

// polyfill, remove me later on
Array.prototype.values = Array.prototype.values || function* () { yield* this };

class Iter {
    constructor(iter)     { this.iter = iter }
    * [Symbol.iterator]() { yield* this.iter }
    static of(...args)    { return this.from(args) }
    static from(args)     { return new this(args.values()) }
    _(gen)                { return new this.constructor(gen.call(this)) }
}

Now, you can throw arbitrary generators into this, both predefined and ad-hoc ones, for example:

let map = fn => function* () {
    for (let a of this)
        yield fn(a);
};

let filter = fn => function* () {
    for (let a of this)
        if (fn(a))
            yield (a);
};

it = Iter.of("d2", "a2", "b1", "b3", "c", "a000")
    ._(map(s => s.toUpperCase()))
    ._(filter(s => s.startsWith("A")))
    ._(function*() {
        for (let x of [...this].sort())
            yield x;
    });

console.log([...it])

这篇关于如何减少链接映射时的迭代减少过滤器?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆