昨日書いたgrepに続き、mapについて調べたことを書いてみました。
mapとは?
grepが「抽出」を行うことに対して、mapは「変換」を行います。
基本的な変換の処理は
変換した配列、ハッシュ = map 条件式 配列
のようになります。
mapを使った配列処理 基本
一番簡単なのは下記のようなプログラムでしょう。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
#!/usr/bin/perl use strict; use warnings; use Data::Dumper; use List::Util 'max'; my @arr=(2,4,5,7,8); #単純に2倍して取り出す my @arr2 = map { $_*2 } @arr; print Dumper \@arr2; #$VAR1 = [ # 4, # 8, # 10, # 14, # 16 # ]; print "\n"; #下記の処理と全く同じです。 my @arr2=(); for my $v ( @arr ){ push @arr2,$v*2 } print "\n"; |
このようにforで展開する処理と基本的には一緒で、より短く表現することができます。
ハッシュを使い、下記のようなコードを書くこともできます。
1 2 3 4 5 6 7 8 9 10 11 12 |
#array_unique @arr =("hoge","foo","bar","hoge"); #下記の例でハッシュを作れる my %unique = map { $_ => 1 } @arr; my @unique2 = keys( %unique); print Dumper \@unique2; #$VAR1 = [ # 'bar', # 'foo', # 'hoge' # ]; |
mapを使った配列、ハッシュ処理 ハッシュを含む多次元配列への応用
例よって実務で一番多い多次元ハッシュタイプの処理での応用例です。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
my $hash_arr =[ {"name"=>" kazumi", "domain"=>"gmail.com", "age"=>"30","pref"=>"chiba"}, {"name"=>"ichirou","domain"=>"yahoo.co.jp", "age"=>"18","pref"=>"tokyo"}, {"name"=>" yuusuke","domain"=>"hotmail.com", "age"=>"25","pref"=>"chiba"}, {"name"=>" satoshi","domain"=>"gmail.com", "age"=>"45","pref"=>"kanagawa"}, {"name"=>"jirou ", "domain"=>"hotmail.com", "age"=>"9","pref"=>"tokyo"} ]; print Dumper $hash_arr; print "\n"; #応用例 #空白が削除されたname+@+domainのメルアドをカンマ区切りで出したい #mapで処理する場合は内部の値を書き換えないこと。リファレンスで処理する場合、内部の値がかわってしまう。 #下記のようにディープコピーをしておくこと #ディープコピー my $hash_arr2 = [map {{%$_}} @$hash_arr]; # 左から空白削除結合を行っている my @email_arr = map{ $_->{"name"} =~ s/ // ; $_->{"name"}."@". $_->{"domain"}; } @$hash_arr2; print join(",",@email_arr); print "\n"; #kazumi@gmail.com,ichirou@yahoo.co.jp,yuusuke@hotmail.com,satoshi@gmail.com,jirou@hotmail.com #番外編 一部の変数を変換 ※下記のような変換作業に対してmapを使うべきではない・・通常はforeachを使うべき my @hash_arr3 = map{ { "name"=>$_->{"name"}, "age"=>$_->{"age"}*2, "pref"=>$_->{"pref"}, "domain"=>$_->{"domain"} }} @$hash_arr; print Dumper \@hash_arr3; print "\n"; |
ハッシュの展開
mapの使用例ではないのですが、ハッシュの出力をかいておきます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
my $hash_arr =[ {"name"=>"kazumi","age"=>"30","pref"=>"chiba"}, {"name"=>"ichirou","age"=>"18","pref"=>"tokyo"}, {"name"=>"yuusuke","age"=>"25","pref"=>"chiba"}, {"name"=>"satoshi","age"=>"45","pref"=>"kanagawa"}, {"name"=>"jirou","age"=>"9","pref"=>"tokyo"} ]; #通常のループ処理 for my $person_hash (@$hash_arr){ while( my ( $key, $value ) = each %$person_hash ){ print $key ." : " . $value; print " "; } print "\n"; } #pref : chiba name : kazumi age : 30 #pref : tokyo name : ichirou age : 18 #pref : chiba name : yuusuke age : 25 #pref : kanagawa name : satoshi age : 45 #pref : tokyo name : jirou age : 9 print "\n"; |
eachというのはかなり有名なようですが、知らない方もいるようですね。
知っておくとできることの幅が広がってよいと思います。
参考リンク
【perl】grep、mapでいろいろやる(配列からkey=>1のhashに変換、リストからユニークな値の取得、2つの配列をマッピングしてhashに変換)