作者: Tsutomu Hiroshima
日時: 2002/11/19(11:55)
廣島です.
週末は留守にしていました.

くすのきさん> perl の比べてどうですか、「短い」スクリプトになっていますか?

廣島> 実際には文字列データから正規表現で
廣島> 数値部分を取り出しつつ処理する必要があり,

と言うわけで,間に余計な部分が挟んであります.
「お題」の部分の長さは,同じぐらいでしょうか.
ロジックは かわじさん(Ruby 版)と同じく
「2 変数(連番開始と終了)で処理」
と同じでした.

「お題」を提案後考えたのは,
「リストを破壊しつつ処理する」ロジックです.
高橋さんの Tcl 版に似ています,

1) 与えられたリストの先頭から連番になっている部分リストを除去し,
2) 除去した部分リストの先頭と末尾を '-' でつなぐ.
3) 与えられたリストが空になるまで 1, 2 を繰り返す.

このロジックで作ったのが,seqfind1 と seqfind2 です.
# 1) の部分は今のところ単なる線形検索でやっています.
# リストが長く,欠番が少ない場合には効率が悪くなるので,
# 重みつきの 2 分木検索で最初の欠番を探すのが良いと思います.
# (次の「お題」か? スクリプトが見にくくなるだけ?)

seqfind3 は,処理効率は無視し,分かりやすいロジックを重視して
「正規表現を使用」しました.

1,2,3,5,7,8,10,12,14,15,16,17 を,
1-2-3,5,7-8,10,12,14-15-16-17 と言う文字列に変換し,
"ハイフンの連続" を 1 つのハイフンに置き換える方法です.

高橋さんの「サブリストに分類」のアイデアと共通するものがあります.
#これがいちばん短いかな?


#!/usr/bin/perl

@list = (1, 2, 3, 5, 7, 8, 10, 12, 14, 15, 16, 17);

sub seqfind1 {
  my @ret;
  while (@_) {
    my $a = $_[0];
    my $i = 1;
    while ($a + $i == $_[$i]) {
      $i ++;
    }
    my @sub = splice @_, 0, $i;
    push @ret, scalar @sub == 1 ? $sub[0] : "$sub[0]-$sub[-1]";
  }
  return join(',', @ret);
}

sub seqfind2 {
  my @ret;
  while (@_) {
    my $a = shift;
    my $b = $a;
    my $i = 1;
    while ($a + $i == $_[0]) {
      $i ++;
      $b = shift;
    }
    push @ret, $a == $b ? $a : "$a-$b";
  }
  return join(',', @ret);
}

sub seqfind3 {
  my $ret = $_[0];
  for (my $i = 1; $i < scalar @_; $i ++) {
    my ($a, $b) = @_[$i - 1, $i];
    $ret .= ($a + 1 == $b ? '-' : ',') . $b;
  }
  $ret =~ s/-(\d+-)+/-/g;
  return $ret;
}

print seqfind1(@list), "\n";
print seqfind2(@list), "\n";
print seqfind3(@list), "\n";

__END__

-----------------------------
	廣島 勉
	(tsutomu@...)