2012年01月04日 21:00 [Edit]

algorithm - mapBetween - 配列の隣接する2項にそれぞれ演算を施した配列

言語を増やしたかったのと、そういう関数に名前を付けたかったのとで1 entry割くことにしました。

等差数列 - タイトル
配列の隣接する2項にそれぞれ演算を施した配列を得たい。つまり、
f (+) [1,2,3,4,5] = [3,5,7,9]
のような f が欲しい。

名前

もちろん等差数列を作るのにもこの関数は使えるのですが、この一般的に使える関数に使う名前としてはあまりに局所的。というわけで mapBetween としてみました。使いどころはかなり多そうです。各言語に標準装備されていないのがちょっと不思議なほど。

JavaScriptによる実装

Array.prototype.mapで滅多に使われない第二引数を使ってみました。

Array.prototype.mapBetween = function(callback, thisArg) {
    return this.slice(0, -1).map(function(v, i) {
        return callback.call(thisArg, v, this[i]);
    }, this.slice(1));
};

Perlによる実装

map BLOCK LISTのBLOCKの呼び出しではスタックを積まない、つまり@_がそのままである点に気が付くと以下のように書けます。

use 5.012;

sub mapBetween(&@) {
    map { $_[0]->( $_[$_], $_[ $_ + 1 ] ) } 1 .. @_ - 2;
}

say '# ', join ",", mapBetween { $_[1] - $_[0] } ();
say '# ', join ",", mapBetween { $_[1] - $_[0] } (0);
say '# ', join ",", mapBetween { $_[1] - $_[0] } (0, 1);
say '# ', join ",", mapBetween { $_[1] - $_[0] } (0, 1, 4);
say '# ', join ",", mapBetween { $_[1] - $_[0] } (0, 1, 4, 9);

ただしCORE::sort()List::Utils()などで見られる、引数の代わりに$a$bを使う記法にも対応させようとすると少し工夫が必要となります。こんなところでしょうか。

use 5.012;

sub mapBetween(&@) {
    my $pkg = caller();
    no strict 'refs';
    map {
        local ( ${ $pkg . '::a' }, ${ $pkg . '::b' } ) =
          ( $_[$_], $_[ $_ + 1 ] );
        $_[0]->( $a, $b )
    } 1 .. @_ - 2;
}

{
    our ( $a, $b ) = ( 'a', 'b' );
    say '# ', join ",", mapBetween { $b - $a } ();
    say '# ', join ",", mapBetween { $b - $a } (0);
    say '# ', join ",", mapBetween { $b - $a } ( 0, 1 );
    say '# ', join ",", mapBetween { $b - $a } ( 0, 1, 4 );
    say '# ', join ",", mapBetween { $b - $a } ( 0, 1, 4, 9 );
    say $a, $b;
}
{
    package NotMain;
    our ( $a, $b ) = ( 'A', 'B' );
    say '# ', join ",", main::mapBetween { $b - $a } ();
    say '# ', join ",", main::mapBetween { $b - $a } (0);
    say '# ', join ",", main::mapBetween { $b - $a } ( 0, 1 );
    say '# ', join ",", main::mapBetween { $b - $a } ( 0, 1, 4 );
    say '# ', join ",", main::mapBetween { $b - $a } ( 0, 1, 4, 9 );
    say $a, $b;
}

Enjoy!

Dan the Mapper in between


この記事へのトラックバックURL

この記事へのトラックバック
Squeak Smalltalk には overlappingPairsCollect: という名前で標準装備されています。 もちろん等差数列を作るのにもこの関数は使えるのですが、この一般的に使える関数に使う名前としてはあまりに局所的。というわけで mapBetween としてみました。使いどころはかなり多そ
[OOPL] Re: 配列の隣接する2項にそれぞれ演算を施した配列【Smalltalkのtは小文字です】at 2012年01月05日 08:35
404 Blog Not Found:algorithm – mapBetween – 配列の隣接する2項にそれぞれ演算を施した配列 等差数列 – タイトル 配列の隣接する2項にそれぞれ演算を施した配列を得たい。つまり、 f (+) [1,2,3,4,5] = [3,5,7,9] のような f が欲しい。 C#でもやってみましょう。 using
C#でもMapBetween【be free】at 2012年01月04日 23:49
404 Blog Not Found:algorithm – mapBetween – 配列の隣接する2項にそれぞれ演算を施した配列 等差数列 – タイトル 配列の隣接する2項にそれぞれ演算を施した配列を得たい。つまり、 f (+) [1,2,3,4,5] = [3,5,7,9] のような f が欲しい。 C#でもやってみましょう。 using
C#でもMapBetween【be free】at 2012年01月04日 23:44
この記事へのコメント
F# で普通に
let mapBetween f sq = Seq.windowed 2 sq |> Seq.map (Seq.reduce f)
Posted by p-1956050 at 2012年01月06日 18:10