2009-04-06 22 views
20

私は可能な値のリストを持っている:Perlの配列(リスト)に値が存在することを確認する方法はありますか?

@a = qw(foo bar baz); 

私は値$val@a中に存在するかしないことを簡潔な方法で確認する方法を教えてください。

明確な実装はリストをループすることですが、私は確信していますTMTOWTDI


すべての方に感謝します!私はハイライトしたい3の答えは以下のとおりです。

  1. 受け入れ答え - 最も「ビルトイン」と下位互換性の方法。

  2. RET's answerが最もクリーンですが、Perl 5.10以降でのみ有効です。

  3. draegtun's answer(おそらく)少し速く、追加のモジュールを使用する必要があります。依存関係を避けることができない場合は依存関係を追加するのが好きではありません。この場合、パフォーマンスの差は必要ありませんが、1,000,000要素のリストがあれば、この回答を試してみてください。

+1

を実装して、不必要な依存関係が気に入らない場合:: Utilの。これはPerlの標準であり、qw/first /(Draegtunのように)を使用すると、1つのサブルーチンしかインポートできません。 – Telemachus

+0

それ自体は問題ではなく、もっと個人的な好みです。 – MaxVT

+1

List :: Utilの回答に依存する問題はありません。それが私だったら、それは受け入れられる答えだろう。コアモジュールを使用することの不毛は、私を迷信に惑わされます。この場合、grep {}はほぼ同じくらい良いです。 – singingfish

答えて

20

Perlのはgrepでエージェントbulit()関数は、これを行うために設計されています。特に繰り返し検索に

+0

+1ねえ!シンプルで素敵な=)ありがとう – Viet

8

考えられるアプローチの1つは、List :: MoreUtils 'any'関数を使用することです。

use List::MoreUtils qw/any/; 

my @array = qw(foo bar baz); 

print "Exist\n" if any {($_ eq "foo")} @array; 

更新:zoulさんのコメントに基づいて補正。

my %hash; 
map { $hash{$_}++ } @a; 
print $hash{$val}; 
+0

Defined( "foo")は常にtrueです。$ _ eq 'foo'を意味しましたか? – zoul

+0

-1申し訳ありませんが、記載されているzoulについて。 –

+0

ええ、それは{$ _ eq "foo"}か{m/^ foo \ z /}のいずれかである必要があります... – jettero

5

興味深いソリューション、。

@matches = grep(/^MyItem$/, @someArray); 

か、perlの5.10を持っている場合は、整合

@matches = grep($_ == $val, @a); 
+0

Zoulのハッシュについての提案はかなり最適ですが、プログラムの過程で配列に値を追加したり削除したりすることで、ハッシュ値を追加して削除することをお勧めします。 –

+0

また、これはうまくいくものの、一般的なものですが、(私が推測すると思いますが)一部の人々は、voidコンテキストでマップを使用することについて不満を持ちます。代わりに@aの$ hash {$ _} ++を使用してみませんか? – jettero

+0

はい、それはよかったです。 – zoul

38

に任意の式を挿入することができますが、それはほとんど魔法だsmart-match operator ~~

print "Exist\n" if $var ~~ @array;

を使用しています。

+0

NB。 5.10.1から、セマンティクスは少し変更されました: 'if $ var ~~ @ array'。 '~~'を 'のように考えるのを助けるために。 ref:http://perldoc.perl.org/perldelta.html#Smart-match-changes – draegtun

+0

ありがとうございます - それに応じて注文を交換しました。 – RET

+1

私のperldoc urlはもはや有効ではありません。ここに固定されています:http://search.cpan.org/~dapm/perl-5.10.1/pod/perl5101delta.pod#Smart_match_changes – draegtun

2
$ perl -e '@a = qw(foo bar baz);$val="bar"; 
if (grep{$_ eq $val} @a) { 
    print "found" 
} else { 
    print "not found" 
}' 

NBは

use List::Util qw/first/; 

my @a = qw(foo bar baz); 
if (first { $_ eq 'bar' } @a) { say "Found bar!" } 

.... Perlで標準装備List::Utilから最初関数を使用し

15

を見つけていない

​​

を見つけました。最初には見つかった最初の要素を返します。したがって、完全なリストを反復する必要はありません(grepのようになります)。

+1

foolishbratごとに、インポートされたサブを使用する場合、私はList :: MoreUtil :: any()は、LISTの項目が基準を満たしている場合に真の値を返すため、意味的にはfirst()( "BLOCKの結果が真の値である最初の要素を返します。 ") – nohat

+0

List :: Util :: first()は、コアモジュール(すなわちユビキタス)であるという利点があります。もし私がCPANオプションを探していたら、私は真剣にPerl6 :: Junction :: anyを考えるでしょう。if(any(@a)eq 'baz'){} – draegtun

18

の回答は"How can I tell whether a certain element is contained in a list or array?"です。

perlfaqを検索するには、perlfaqのすべての質問のリストから、お気に入りのブラウザを使用して検索できます。

コマンドラインから、perldocに-qスイッチを使用してキーワードを検索することができます。あなたは、「リスト」を検索することで、あなたの答えを見つけているだろう:

perldoc -q list 

公聴会「の」ワード(安野シーゲルとブライアンd foyによって寄贈されましたこの答えの部分)が表示されますリストや配列ではなく、ハッシュを使用してデータを格納しているはずです。ハッシュは、この質問にすばやく効率的に答えるように設計されています。配列はありません。

これは、これにはいくつかの方法があります。 5.10以降では、あなたはアイテムが配列やハッシュに格納されていることを確認するために、スマートマッチ演算子を使用することができますPerlの以前のバージョンでは

use 5.010; 

if($item ~~ @array) 
    { 
    say "The array contains $item" 
    } 

if($item ~~ %hash) 
    { 
    say "The hash contains $item" 
    } 

、あなたは少しより多くの仕事をしなければなりません。今、あなたは$かどうかを確認することができ

@blues = qw/azure cerulean teal turquoise lapis-lazuli/; 
%is_blue =(); 
for (@blues) { $is_blue{$_} = 1 } 

:あなたはこのクエリに任意の文字列の値に比べて多くの時間を作るしようとしている場合は、最速の方法は、キーが最初の配列の値であり、ハッシュを元の配列を反転し、維持することが考えられますis_blue {$ some_color}。最初の場所でブルーをすべてハッシュに保つことは良い考えでした。

値がすべて小さい整数の場合は、単純なインデックス付き配列を使用できます。この種の配列は、より少ないスペースを占有します。

@primes = (2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31); 
@is_tiny_prime =(); 
for (@primes) { $is_tiny_prime[$_] = 1 } 
# or simply @istiny_prime[@primes] = (1) x @primes; 

ここで、$ is_tiny_prime [$ some_number]がチェックされています。

問題の値は、整数の代わりに文字列である場合は、代わりにビット列を使用してスペースのかなり多くを保存することができます。

@articles = (1..10, 150..2000, 2017); 
undef $read; 
for (@articles) { vec($read,$_,1) = 1 } 

今VECは($、$ nは、1を読んで)であるかどうかを確認一部の$ nでは真です。

これらのメソッドは、迅速な個別テストを保証しますが、元のリストまたは配列の再編成を必要とします。同じ配列に対して複数の値をテストする必要がある場合にのみ効果があります。

標準モジュールList :: Utilは、この目的のために関数を最初にテストします。要素が見つかると停止します。これは、速度のためにCで書かれており、そのPerlの同等はこのサブルーチンのように見えます:

sub first (&@) { 
    my $code = shift; 
    foreach (@_) { 
     return $_ if &{$code}(); 
    } 
    undef; 
} 

速度がやや懸念される場合は、一般的なイディオムは(その条件を通過したアイテムの数を返します)スカラーコンテキストではgrepを使用していますリスト全体をトラバースする。しかし、これで見つかったマッチの数が分かるというメリットがあります。

my $is_there = grep $_ eq $whatever, @array; 

実際に一致する要素を抽出するには、リストコンテキストでgrepを使用します。

my @matches = grep $_ eq $whatever, @array; 
1

あなたは私が一覧で依存関係の問題を見ていることはよく分からないanyまたはfirst自分

sub first (&@) { 
    my $code = shift; 
    $code->() and return $_ foreach @_; 
    undef 
} 

sub any (&@) { 
    my $code = shift; 
    $code->() and return 1 foreach @_; 
    undef 
} 
関連する問題