Perlでハッシュの取り出し順序を補償する方法
普通にやる場合、Tie::IxHashを使うのが楽ですが、
今回は自前実装してみました。
package Sorauta::Util::Iterator; use 5.010000; use strict; use warnings; use Carp qw/croak/; our($YES, $NO) = qw/1 0/; #===================== # #===================== sub new { my $self = shift; bless { _last_id => 0, _position => 0, _item_key_list => [], _item_list => {}, }, $self; } # リストをセット # ハッシュのリファレンスを渡す sub hash2itr { my($self, $hash_ref) = @_; #$self->{_last_id} = 0; #$self->{_position} = 0; #$self->{_item_key_list} = []; #$self->{_item_list} = {}; while (my($key, $val) = each(%$hash_ref)) { $self->add($key, $val); } } # 最後尾に追加する sub add { my($self, $key, $val) = @_; $self->{_item_list}->{$key} = $val; $self->{_item_key_list}->[$self->{_last_id}++] = $key; return ; } # 削除する sub del { my($self, $key) = @_; # ハッシュを削除 delete($self->{_item_list}->{$key}); # インデックス保持配列削除 my $index = -1; foreach (0..@{$self->{_item_key_list}}) { if ($self->{_item_key_list}->[$_] eq $key) { $index = $_; last; } } if ($index == -1) { croak 'not found key'; } splice(@{$self->{_item_key_list}}, $index, 1); # 個数を減らす $self->{_last_id}--; return ; } # キー指定で取得 # ※ただし、_positionの移動などは行わない sub get { my($self, $key) = @_; return $self->{_item_list}->{$key}; } # インデックス指定で取得 # ※ただし、_positionの移動などは行わない sub get_by_index { my($self, $index) = @_; my $key = $self->{_item_key_list}->[$index]; return $self->{_item_list}->{$key}; } # 次へ sub next { my $self = shift; my $key = $self->{_item_key_list}->[$self->{_position}++]; if ($self->{_position} <= $self->{_last_id}) { return $self->{_item_list}->{$key}; } else { return ; } } # 次があるか sub hasNext { my $self = shift; return $self->{_position} < $self->{_last_id} ? $YES : $NO; } # ポジションを最初に戻す sub reset { my $self = shift; $self->{_position} = 0; return; } # 全行取得 sub all { my $self = shift; my @list = (); foreach my $val(values(%{$self->{_item_list}})) { push(@list, $val); } return wantarray ? @list : \@list; } # 件数返却 sub count { my $self = shift; return $self->{_last_id}; } 1;
とりあえず必要そうな機能はある程度盛り込んだはず。
使い方はこんな感じ。
追加: my $itr = Sorauta::Util::Iterator->new; $itr->add('num1', { data => 1, test => "fuck" }); $itr->add('num2', [ 'data', 1, 'test', "fuck" ]); $itr->add('num3', 'kurenai'); $itr->add('num4', 109238402389); $itr->add('sub_ref', $sub_ref); # $sub_ref = sub { print 'hoge' }; 削除: my $itr = Sorauta::Util::Iterator->new; $itr->del('key'); 取得: my $itr = Sorauta::Util::Iterator->new; my $val = $itr->get('num1'); my $val = $itr->get_by_index(3); いてレータっぽくする: my $itr = Sorauta::Util::Iterator->new; while (my $val = $itr->next) { print Dumper($val); } 次持ってるか確認: say $itr->hasNext ? 'you have next value' : 'none'; 配列にして全部取得: my $itr = Sorauta::Util::Iterator->new; my $list = $itr->all; or my @list = $itr->all; 件数取得: my $count = $itr->count; ハッシュから変換する: my $itr2 = Sorauta::Util::Iterator->new; my $hash_list = { hoge => 1, sample => 2, wieht => [1,2,3,5,55,2524352345,23], hash => {shi => 1, weoith=>"2", weotj => "hoghehoge"} }; $itr2->hash2itr($hash_list); while (my $val = $itr2->next) { print Dumper($val); #=> 1, 2, {shi=>1,...}... } 先頭に戻す: $itr->reset;
一応、CPANにもあげておきました。
車輪の再発明すぎて不要とは思いますが...
http://search.cpan.org/~yuki/Sorauta-Util-Iterator-0.01/lib/Sorauta/Util/Iterator.pm