perlで「約3,000個の連続番号にそれぞれ文字列を割り当てて(1-3番まではhoge、4-5番まではfuga、6-10番まではfugo...のように)、番号を指定したときに対応する文字列を取り出す」ということを実現させたいです。

(例)
 $number_string->ref(1) # hoge
 $number_string->ref(8) # fugo

DBに3000組を連番で突っ込む、という方法は思いつきますが、ちょっとした文字列を取り出すのにいちいちDBにアクセスするのは処理が遅くなりそうなので避けたいです。
なにか良い方法はないでしょうか。ご教授願いたいです。

回答の条件
  • 1人1回まで
  • 登録:2010/06/07 13:30:41
  • 終了:2010/06/12 07:56:51

ベストアンサー

id:y-kawaz No.1

y-kawaz回答回数1419ベストアンサー獲得回数2252010/06/07 15:13:32

ポイント35pt

常駐プログラムでメモリも十分になる場合は、短い文字列3000個程度であれば単純に配列に突っ込んでおくとかでいい気がします。

@number_string=(
  "zero", #0
  "hoge","hoge","hoge", #1-3
  "fuga","fuga","fuga", #4-6
  "fugo","fugo","fugo","fugo", #6-10
);

$number_string[1] # hoge
$number_string[8] # fugo

実際はソースにデータテーブルを全部書くのではなく、最初に一度だけファイルを配列に読み出す処理を行うとかで良いと思いますが。

id:Cside

ありがとうございます。

メモリの負担にならないかがちょっと心配ですが

(3000個の文字列(1個あたり20文字ほど)がメモリにどの程度の負担になるのかは勉強不足で分からないのですが)、

最も簡単かつ確実な方法ですね。

2010/06/07 15:19:28

その他の回答(1件)

id:y-kawaz No.1

y-kawaz回答回数1419ベストアンサー獲得回数2252010/06/07 15:13:32ここでベストアンサー

ポイント35pt

常駐プログラムでメモリも十分になる場合は、短い文字列3000個程度であれば単純に配列に突っ込んでおくとかでいい気がします。

@number_string=(
  "zero", #0
  "hoge","hoge","hoge", #1-3
  "fuga","fuga","fuga", #4-6
  "fugo","fugo","fugo","fugo", #6-10
);

$number_string[1] # hoge
$number_string[8] # fugo

実際はソースにデータテーブルを全部書くのではなく、最初に一度だけファイルを配列に読み出す処理を行うとかで良いと思いますが。

id:Cside

ありがとうございます。

メモリの負担にならないかがちょっと心配ですが

(3000個の文字列(1個あたり20文字ほど)がメモリにどの程度の負担になるのかは勉強不足で分からないのですが)、

最も簡単かつ確実な方法ですね。

2010/06/07 15:19:28
id:imo758 No.2

imo758回答回数121ベストアンサー獲得回数192010/06/08 15:09:50

ポイント35pt

少し大変になりますがStorableモジュールを使うと微かに早くできるかもしれません。

予めStorableでデータを固めておきます。

use Storable qw(nstore_fd fd_retrieve);

@num_str=(
  "zero", #0
  "hoge","hoge","hoge", #1-3
  "fuga","fuga","fuga", #4-6
  "fugo","fugo","fugo","fugo", #6-10
);
  $fn='num_str.dat';
  open G, ">$fn" or die "cannot open $fn";
  nstore_fd \@num_str, \*G;

このスクリプトは少々時間がかかってもOKです。

普段頻繁に使うスクリプトでは、Storableで保存したデータファイルを読み込みます。

use Storable qw(nstore_fd fd_retrieve);

  $fn='num_str.dat';
  open G, "<$fn" or die "cannot open $fn";
  $num_str = fd_retrieve(\*G);
#  @num_str = @{fd_retrieve(\*G)};
  print @{$num_str};
#  print @num_str;

ただしStorableモジュールによるオーバーヘッドがありますので、巨大なデータでないとかえって遅くなってしまいます。それになにより下準備が面倒です。

他にも、データを100個くらいに区切って別個のファイルに格納し必要なファイルだけ読み込む、データファイルをRAMディスクに置く、配列にデータを格納したままプロセスを休止させプロセス間通信を使う、などの様々な方法が思い浮かびますが、3000個程度のデータだと、実際に試してみないとどれが一番効果的かはわかりません。

身も蓋もないことを言ってしまうと、そのくらいの処理ならば気にしないのが一番の解決法かもしれません。

id:Cside

おお、こんなモジュールがあるのですね。

今回の3,000個のデータは配列等で処理した方が良いみたいですが、

万単位のデータを扱うときにはとても便利そうですね。

2010/06/08 16:26:24
  • id:b-wind
    >3000個の文字列(1個あたり20文字ほど)
    英数字のみであれば 1byte / 1文字程度。
    3000 * 20 * 8 = 480000byte ≒ 468KByte
    実際には Perl のメタ情報と配列のオーバーヘッドも含むからもう少し多くなるだろうけど、倍と見積もっても
    1MB程度に満たない。

    正確に知りたければ Devel::Size なんてのもあるね。
    http://perldoc.jp/docs/modules/Devel-Size-0.58/Size.pod

  • id:b-wind
    >万単位のデータを扱うとき
    いや、Storable なら使うときに全データ展開しないといけないんで常時メモリを
    使用することは無いもののあまりうれしくはない。

    その規模でやってRDBMSに抵抗があるなら各種DBM使うのがいいんじゃない?
    http://search.cpan.org/dist/perl/lib/AnyDBM_File.pm
    使うときは単なるハッシュと同じ使い方でメモリに関しては裏で良きに計らってくれる。
    データや環境によるけど gdbm あたりなら大抵の用途で問題は無いと思う。
  • id:Cside
    おお、DBM、良さそうですね!すぐに試してみます。

この質問への反応(ブックマークコメント)

「あの人に答えてほしい」「この質問はあの人が答えられそう」というときに、回答リクエストを送ってみてましょう。

これ以上回答リクエストを送信することはできません。制限について

絞り込み :
はてなココの「ともだち」を表示します。
回答リクエストを送信したユーザーはいません