読者です 読者をやめる 読者になる 読者になる

Re: [1,2,3,4,5] が与えられたとき [[1,2][2,3][3,4][4,5]] を返すような関数を定義せよ

perl

vallog: [1,2,3,4,5] が与えられたとき [[1,2][2,3][3,4][4,5]] を返すような関数を定義せよ

Perlで解いてみた。

プログラム

こんな感じでしょうか。モジュールは特に使ってないです。素のperlでも
もう少しエレガントな回答があるかもしれないですね。

#!/usr/bin/env perl
use strict;
use warnings;

sub overlap_slices {
    my ($array_ref, $length) = @_;

    die "argument is undef\n" unless defined $array_ref;

    $length ||= 2;

    my @array = @{$array_ref};
    my $ret = [];
    while (scalar @array >= $length) {
        my @cars = splice @array, 0, ($length - 1);
        my $cadr = $array[0];

        push @{$ret}, [@cars, $cadr];
    }

    my $reminder = scalar @array;
    push @{$ret}, [@array] if $reminder > 1 && $reminder <= ($length - 1);

    return $ret;
}

テスト

ちゃんとテストファーストでやったら、やっぱり効率的ですね。

use Test::More;

my ($got, $expected);

$got = overlap_slices([]);
is_deeply($got, [], "empty array");

$got = overlap_slices([0, 1]);
is_deeply($got, [[0, 1]], "only two elements");

$expected = [
    [0, 1], [1, 2], [2, 3], [3, 4], [4, 5],
];

$got = overlap_slices([0..5]);
is_deeply($got, $expected, "default length 2");

$got = overlap_slices([0..9], 2);
$expected = [
    [0,1], [1,2], [2,3], [3,4], [4,5],
    [5,6], [6,7], [7,8], [8,9],
];

is_deeply($got, $expected, "length is 2");

$got = overlap_slices([0..9], 3);
$expected = [
    [0..2], [2..4], [4..6], [6..8], [8,9],
];

is_deeply($got, $expected, "length is 3");

$got = overlap_slices([0..9], 4);
$expected = [
    [0..3], [3..6], [6..9],
];

is_deeply($got, $expected, "length is 4");

$got = overlap_slices([0..9], 5);
$expected = [
    [0..4], [4..8], [8,9],
];

is_deeply($got, $expected, "length is 5");

$got = overlap_slices([0..9], 6);
$expected = [
    [0..5], [5..9],
];

is_deeply($got, $expected, "length is 6");

$got = overlap_slices(['a'..'z'], 10);
$expected = [
    ['a'..'j'], ['j'..'s'], ['s'..'z'],
];

is_deeply($got, $expected, "length is 10");

done_testing;

テスト結果

% prove -v test1.pl
test1.pl .. 
ok 1 - empty array
ok 2 - only two elements
ok 3 - default length 2
ok 4 - length is 2
ok 5 - length is 3
ok 6 - length is 4
ok 7 - length is 5
ok 8 - length is 6
ok 9 - length is 10
1..9
ok
All tests successful.
Files=1, Tests=9,  0 wallclock secs ( 0.03 usr  0.00 sys +  0.02 cusr  0.00 csys =  0.05 CPU)
Result: PASS

正しいようです。

まとめ

リスト処理の問題を Perlで問いてみました。やっぱりリスト処理は
Lisp系の言語の方がすっきり書けるかなと思いました。Lisp系の勉強をして
Perlでもリスト処理がエレガントに回答できるようになりたいものです。