LoginSignup
1
0

More than 1 year has passed since last update.

【javascript】filterMap()をジェネレータ関数を使って作ってみた

Last updated at Posted at 2021-05-08

前置き

//これを
array.filter().map()
//こうしたかった
array.filterMap()

ざっくり言いますと
filter()map()callback関数ジェネレータ関数で処理するようにしただけです。
引数は同様。
最初のyieldfilter()、2回目のyieldmap()

「こんなのがあったらいいな」というものなので、実用に耐え得るか否かはわかりません。

function

const filterMap = (arr, generator) => {
    try {
        if (!Array.isArray(arr)) {
            throw new Error('1st arg : not Array');
        }
        if (typeof generator!=='function'
             || generator.constructor.name!=='GeneratorFunction') {
            throw new Error('2nd arg : not GeneratorFunction');
        }
        const array = arr.slice();
        const result = [];
        for (let i=0,m=array.length; i<m; i++) {
            const gen = generator(array[i], i, array);
            if ( gen.next().value ) {
                result.push( gen.next().value );
            }
            gen.return();
        }
        return result;
    } catch(e) {
        console.error(e);
    }
};
const arr = [0,1,7,2,1,3,4,5,9,4,5,0,8,3,5,7,4,4];

//値が5のindexを出力
const idx5 = filterMap(arr, function*(x,i,a) {
    yield x===5;    //filter
    yield i         //map
});
console.log( idx5 );    //  [7, 10, 14]


const chunk = filterMap([...Array(10).keys()], function*(x,i,a) {
    yield i%3===0;          //filter
    yield a.slice(i, i+3);  //map
});
console.log( chunk );   //[[0, 1, 2], [3, 4, 5], [6, 7, 8], [9]]

Array.prototype

if (!Array.prototype.filterMap) {
    Object.defineProperty(Array.prototype, 'filterMap', {
        value: function(generator) {
            try {
                if (typeof generator!=='function'
                     || generator.constructor.name!=='GeneratorFunction') {
                    throw new Error('arg is not a GeneratorFunction');
                }
                const array = this.slice();
                const result = [];
                for (let i=0,m=array.length; i<m; i++) {
                    const gen = generator(array[i], i, array);
                    if ( gen.next().value ) {
                        result.push( gen.next().value );
                    }
                    gen.return();
                }
                return result;
            } catch(e) {
                console.error(e);
            }
        },
    });
}
const arr = [0,1,7,2,1,3,4,5,9,4,5,0,8,3,5,7,4,4];

//値が5のindexを出力
const idx5 = arr.filterMap(function*(x,i,a) {
    yield x===5;    //filter
    yield i         //map
});
console.log( idx5 );    //  [7, 10, 14]


const chunk = [...Array(10).keys()].filterMap(function*(x,i,a) {
    yield i%3===0;          //filter
    yield a.slice(i, i+3);  //map
});
console.log( chunk );   //[[0, 1, 2], [3, 4, 5], [6, 7, 8], [9]]

補足

const idx5 = arr.filterMap(function*(x,i,a) {
    yield x===5;    //filter
    yield i         //map
});

処理が単純であればyield* [filter, map]でまとめられます。

const idx5 = arr.filterMap(function*(x,i,a) {
    yield* [x===5, i];      // [filter, map]
});

私感・妄想

ジェネレータ関数にもアロー関数のような略した書き方がほしい。

妄想.js
//これを
function*(x,i) {
    yield* [x===5, i];
});

//こうして
(x,i) *> {
    yield* [x===5, i]
};

//更にこうして
(x,i) **> [x===5, i];

//こうなる
const idx5 = arr.filterMap((x,i) **> [x===5, i]);
妄想2.js
//こういうのも
function* increase(n) {
    while (true) yield n++;
});

//こう…欲張りすぎか
const increase = n **> n++;

なんてね

参考

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0