• 締切済み

perlで2つの配列を比較する方法について

こんにちは、perlについての質問です。 2つの配列を比較するで調べたところ、"@deff = grep { !{map{$_,1}@array2 }-> {$_}}@array1;"で比較ができると書かれていました。perl初心者ですので、よくわからず、自分なりにこの処理について調べてみましたが、わかりませんでした。この処理の詳細がわかる方いましたら、教えてください。(特にmap($_,1)@array2 の部分がよくわからなかったです) よろしくお願いします。

みんなの回答

  • kabaokaba
  • ベストアンサー率51% (724/1416)
回答No.3

関数型プログラムになれてれば 読めるコードですけど,Perl風味が混じってるので ちょっとしんどいですね. リファレンスを知ってるかどうかが重要です. {map{$_,1}@array2 }-> {$_} ここが何をしてるのかわかれば,大体OKかな map{$_,1}@array2 の部分では,@array2の要素を一個じつ$_1にいれて 1とペアにしています.たとえば,@array2=(a,b,c,d)だったら aを$_にして,a,1 をつくって bを$_にして,b,1をつくって・・・とやって (a,1,b1,c,1,d,1) というリストを作ります.これがmapの機能 これを { } で囲んで { (a,1,b1,c,1,d,1) } というのを作るんだけども,これは { a,1,b1,c,1,d,1 } と同じで,無名のハッシュ(ハッシュのリファレンス)を 作る.つまり {a=>1, b=>1, c=>1, d=>1} と同じ. リストをそのままハッシュに変換できるということと,それを 無名ハッシュのコンストラクタで処理してるところが かなりPerl風味です. このハッシュリファレンスに対して >{map{$_,1}@array2 }-> {$_} とするんだけども,後ろの$_はgrepが渡してくる @array1の各要素ですので @array1=(a,b,d,x)だとすると a に対しては 1 b に対しては 1 d に対しては 1 x に対しては undef となります. これを ! で否定するのだから a に対しては false b に対しては false d に対しては false x に対しては true がでてきて grepではtrueになるものだけがでてくるので 結果として @deff=(x)となります. 例では, @array1=(a,b,d,x) @array2=(a,b,c,d) なので,これは, @array1の中にあって @array2の中にはない要素を引っ張り出す というのが正しい言い方であって 一概に「配列を比較する」といいきれるかは微妙です. そもそも「配列を比較する」ということ自体が どういう意味かが明確ではないということにも注意が必要です.

回答No.2

> "@deff = grep { !{map{$_,1}@array2 }-> {$_}}@array1;"で比較ができると書かれていました。 もちろんこういうやり方もアリなのですが、初心者の場合後から見た場合に意味が分かる事が重要だと思うので(理解するまでに結構時間がかかった...)次のようなサブルーチンを書いてみました。 サブルーチンにするとどうしても渡された値が正しいかチェックしなければならないため冗長なコードになりますが... sub eq_array (&;$$) { my ($pred, $array1, $array2); if (ref $_[0] eq 'CODE') { # もしも最初が{ ... }だった場合 ($pred, $array1, $array2) = @_; } else { # 普通に配列のリファレンス二つが渡された場合 ($array1, $array2) = @_; } # 配列の数が同じかチェック if (@$array1 != @$array2) { return 0; } for (my $i = 0; $i < @$array2; $i++) { if (defined $pred) { # 最初が{ ... }だった場合 local ($a, $b) = ($array1->[$i], $array2->[$i]); if (! $pred->()) { return 0; } } else { # デフォルトは文字で比較 (sortと同じ) if ($array1->[$i] ne $array2->[$i]) { return 0; } } } # 最後まで一緒だったら真 return 1; } このサブルーチンはsort演算子に動きを合わせてあります。 使い方は文字で比較する場合、 eq_array \@array1, \@array2 と配列のリファレンスを渡してください。 それぞれの要素について $a eq $b で比較されます。 数値で比較する場合はsort演算子のように eq_array { $a == $b } \@array1, \@array2 としてください。 それぞれの要素について $a == $b のように比較されます。 以下このサブルーチンのテストをした時のコードです。 my @array1 = my @array2 = 1 .. 100; printf "equal?:%d\n", eq_array_str(\@array1, \@array2); printf "equal?:%d\n", eq_array_num(\@array1, \@array2); printf "equal?:%d\n", eq_array \@array1, \@array2; printf "equal?:%d\n", eq_array { $a == $b } \@array1, \@array2; @array1 = "a" .. "z"; @array2 = reverse @array1; # use warningsをしていると # 数値に変換できない文字列を # ==で比較すると警告を出してくるので # ここでは数値では比較しない printf "equal?:%d\n", eq_array_str(\@array1, \@array2); # printf "equal?:%d\n", eq_array_num(\@array1, \@array2); printf "equal?:%d\n", eq_array \@array1, \@array2; # printf "equal?:%d\n", eq_array { $a == $b } \@array1, \@array2; 表示結果: equal?:1 equal?:1 equal?:1 equal?:1 equal?:0 equal?:0

回答No.1

#!/usr/bin/perl use warnings; use strict; my @array1 = qw(111 222 333 444 555); my @array2 = qw(222 444); my @diff; # オリジナル @diff = (); @diff = grep { !{ map { $_, 1 } @array2 }->{$_} } @array1; print "---\n"; print $_, " " foreach @diff; print "\n"; # map { $_, 1 } @array2 とほぼ同じ働き my %hash = ( 222, 1, 444, 1); # 上記は%hash = ( 222 => 1, 444 => 1); と同じ @diff = (); @diff = grep { !$hash{$_} } @array1; print "\n---\n"; print $_, " " foreach @diff; print "\n"; # @diff = grep { !$hash{$_} } @array1;とやりたいことは同じ @diff = (); @diff = grep { !(defined $hash{$_}) } @array1; print "\n---\n"; print $_, " " foreach @diff; print "\n";

関連するQ&A