পার্ল অ্যারেতে একটি নির্দিষ্ট মান রয়েছে কিনা তা আমি কীভাবে পরীক্ষা করতে পারি?


239

আমি অ্যারের মাধ্যমে পুনরাবৃত্তি না করে অ্যারের মধ্যে একটি মানের অস্তিত্বের জন্য যাচাই করার উপায়টি বের করার চেষ্টা করছি।

আমি একটি পরামিতি জন্য একটি ফাইল পড়ছি। আমি যে পরামিতিগুলি মোকাবেলা করতে চাই না তার একটি দীর্ঘ তালিকা রয়েছে। আমি এই অযাচিত প্যারামিটারগুলিকে একটি অ্যারে রেখেছি @badparams

আমি একটি নতুন প্যারামিটারটি পড়তে চাই এবং এটি যদি উপস্থিত না থাকে তবে এটি @badparamsপ্রক্রিয়া করুন। যদি এটি বিদ্যমান থাকে @badparamsতবে পরবর্তী পঠনে যান।


3
রেকর্ডের জন্য, উত্তরটি আপনার পরিস্থিতির উপর নির্ভর করে। মনে হচ্ছে আপনি বারবার অনুসন্ধান করতে চান, সুতরাং জ্যাক্রামার পরামর্শ হিসাবে একটি হ্যাশ ব্যবহার করা ভাল। আপনি যদি কেবল একটি অনুসন্ধান করতে চান তবে আপনি সম্ভবত পুনরাবৃত্তি করতে পারেন। (এবং কিছু ক্ষেত্রে আপনি সম্ভবত একটি হ্যাশ ব্যবহারের পরিবর্তে বাইনারি অনুসন্ধান করতে চাইতে পারেন!)
ক্যাসাবেবেল


6
রেকর্ডটির জন্য (এবং এটি আপনার পরিস্থিতির পক্ষে পুরোপুরি প্রয়োগযোগ্য নয়) সাধারণত 'ভাল মানগুলি' চিহ্নিত করা এবং 'খারাপ মানগুলি' বোঝার চেষ্টা না করে বাকিগুলিকে উপেক্ষা করার জন্য এটি একটি ভাল ধারণা। আপনার যে প্রশ্নটি জিজ্ঞাসা করতে হবে তা হ'ল এটি সম্ভব কিনা এমন কিছু খারাপ মান থাকতে পারে যা আপনি এখনও জানেন না।
অনুদান ম্যাকলিন 21

উত্তর:


187

কেবল অ্যারেটিকে হ্যাশে পরিণত করুন:

my %params = map { $_ => 1 } @badparams;

if(exists($params{$someparam})) { ... }

আপনি তালিকায় আরও (অনন্য) প্যারাম যুক্ত করতে পারেন:

$params{$newparam} = 1;

এবং পরে (অনন্য) প্যারামগুলির একটি তালিকা ফিরে পান:

@badparams = keys %params;

38
রেকর্ডের জন্য, এই কোডটি এখনও অ্যারের মাধ্যমে পুনরাবৃত্তি করে। ম্যাপ {The কলটি সেই পুনরাবৃত্তিটি টাইপ করা খুব সহজ করে তোলে।
কেনি ওয়াইল্যান্ড

3
আমি কেবল তখনই এটি করতে পারি যদি @ ব্যাডপ্রেমে আপনার মানগুলি সিউডো-স্ট্যাটিক হয় এবং আপনি মানচিত্রের বিরুদ্ধে প্রচুর চেক করার পরিকল্পনা করেন plan আমি এটি একটি চেকের জন্য সুপারিশ করব না।
অ্যারন টি হ্যারিস

এটি কি একই মান সহ একাধিক আইটেম সহ একটি অ্যারের জন্য ঝাঁকুনি না?
রব ওয়েলস

3
@ রবওয়েলস না, এটি ভাল কাজ করবে। পরের বার এটি একই মান দেখতে পাবে, এটি কেবল হ্যাশটিতে প্রবেশের ওভাররাইট করবে, যা এই ক্ষেত্রে এটি 1আবার সেট করে ।
অ্যান্ড্রুজোনস

222

সেরা সাধারণ উদ্দেশ্য - বিশেষত সংক্ষিপ্ত অ্যারে (1000 আইটেম বা তার চেয়ে কম) এবং কোডারগুলি যা অপ্টিমাইজেশন তাদের প্রয়োজনীয়তার জন্য উপযুক্ত তা সম্পর্কে অনিশ্চিত।

# $value can be any regex. be safe
if ( grep( /^$value$/, @array ) ) {
  print "found it";
}

এটি উল্লেখ করা হয়েছে যে অ্যারে প্রথম মানটি মিললেও গ্রেপ সমস্ত মানগুলির মধ্য দিয়ে যায়। এটি সত্য, তবে গ্রেপ এখনও বেশিরভাগ ক্ষেত্রে অত্যন্ত দ্রুত । আপনি যদি সংক্ষিপ্ত অ্যারে (1000 টিরও কম আইটেম) সম্পর্কে কথা বলছেন তবে বেশিরভাগ অ্যালগরিদম যাইহোক বেশ দ্রুত গতিতে চলেছে। আপনি যদি খুব দীর্ঘ অ্যারে (1,000,000 আইটেম) সম্পর্কে কথা বলছেন তবে গ্রাটটি গ্রহণযোগ্যভাবে দ্রুত হবে তা নির্বিশেষে আইটেমটি প্রথম বা মাঝের বা অ্যারেরে শেষ কিনা।

দীর্ঘতর অ্যারেগুলির জন্য অপ্টিমাইজেশন কেস:

যদি আপনার অ্যারে বাছাই করা হয় তবে একটি "বাইনারি অনুসন্ধান" ব্যবহার করুন।

যদি একই অ্যারেটি বারবার বহুবার অনুসন্ধান করা হয় তবে প্রথমে এটি একটি হ্যাশে অনুলিপি করুন এবং তারপরে হ্যাশটি পরীক্ষা করুন। মেমোরিটি যদি উদ্বেগের বিষয় হয়ে থাকে তবে অ্যারে থেকে প্রতিটি আইটেম হ্যাশে স্থানান্তর করুন। আরও মেমরি দক্ষ তবে আসল অ্যারেটি নষ্ট করে।

যদি একই মানগুলি অ্যারের মধ্যে বারবার অনুসন্ধান করা হয় তবে অলসভাবে একটি ক্যাশে তৈরি করুন। (প্রতিটি আইটেম যেমন অনুসন্ধান করা হয়, প্রথমে অনুসন্ধানের ফলাফলটি একটি অবিরাম হ্যাশে সঞ্চিত ছিল কিনা তা পরীক্ষা করে দেখুন the এটি হ্যাশটিতে সন্ধান করুন এবং অনুসন্ধানটি এড়িয়ে যান)।

দ্রষ্টব্য: দীর্ঘতর অ্যারেগুলি ব্যবহার করার সময় এই অপ্টিমাইজেশানগুলি কেবল দ্রুত হবে। ওভারটিমাইজ করবেন না।


12
পার্ল ৫.১০ এ ডাবল টিলড চালু করা হয়েছিল
পরবর্তী বিজ্ঞপ্তি না দেওয়া পর্যন্ত


5
প্রোডাকশন কোডে স্মার্ট ম্যাচ এড়িয়ে চলুন। এটি অস্থির / পরীক্ষামূলক পরবর্তী বিজ্ঞপ্তি মুলতুবি রয়েছে।
ভেক্টর গর্গোথ

1
আমি এটিকে আরও পঠনযোগ্য বলে মনে করি তবে ব্যবহার করবেন না বলে যে এটি দক্ষ নয় এবং প্রতিটি উপাদান প্রথম হলেও চেক করে।
জিওর্ডানো

7
("মান" ~~ @ অ্যারে) ব্যবহার করবেন না। Smart একটি পরীক্ষামূলক বৈশিষ্ট্য যা স্মার্টমেচ বলে। পরীক্ষাকে ব্যর্থ বলে মনে করা হচ্ছে এবং পার্লের ভবিষ্যতের সংস্করণে সরানো বা সংশোধন করা হবে।
ইয়াহেরমান

120

আপনি পার্ল ৫.১০ তে স্মার্টমেচ বৈশিষ্ট্যটি নিম্নরূপ ব্যবহার করতে পারেন :

আক্ষরিক মান অনুসন্ধানের জন্য নীচে করছেন কৌতুক করবে।

if ( "value" ~~ @array ) 

স্কেলার দেখার জন্য, নীচের কাজগুলি উপরের মতো কাজ করবে।

if ($val ~~ @array)

নীচে ইনলাইন অ্যারে করার জন্য, উপরের মতো কাজ করবে।

if ( $var ~~ ['bar', 'value', 'foo'] ) 

ইন পার্ল 5.18 smartmatch পরীক্ষামূলক হিসাবে পতাকাঙ্কিত করা হয় এর ফলে আপনার চালু করার মাধ্যমে সতর্কবার্তা বন্ধ করতে পরীক্ষামূলক আপনার স্ক্রিপ্টটি / মডিউল করার জন্য নিচের যোগ করে pragma:

use experimental 'smartmatch';

বিকল্প হিসাবে আপনি যদি স্মার্টম্যাচ ব্যবহার এড়াতে চান - তবে হারুন যেমন বলেছিলেন ব্যবহারটি:

if ( grep( /^$value$/, @array ) ) {
  #TODO:
}

4
এটি দুর্দান্ত তবে পার্ল ৫.১০-তে নতুন বলে মনে হচ্ছে। আমি সিনট্যাক্স ত্রুটি কেন করছি তা ভেবে দেখার আগে কিছুটা সময় নিয়েছি।
ইগোর স্কোচিনস্কি

17
সতর্কতা: আপনি সম্ভবত এটিকে এড়াতে চাইতে পারেন, যেহেতু অপারেটর বিভিন্ন সংস্করণে স্পষ্টতই আলাদা আচরণ করেছেন এবং এরই মধ্যে পরীক্ষামূলক হিসাবে চিহ্নিত করেছেন । সুতরাং আপনার পার্ল সংস্করণটির উপরে যদি আপনার সম্পূর্ণ নিয়ন্ত্রণ না থাকে (এবং যার কাছে রয়েছে) আপনার সম্ভবত এটি এড়ানো উচিত।
গত

1
কেন সেটিংয়ের প্রস্তাব দেওয়া হচ্ছে সে সম্পর্কে এই ব্যাখ্যাটি আমি পছন্দ করি use experimental 'smartmatch'। আমার পার্ল সংস্করণ (অভ্যন্তরীণ সিস্টেম) এর নিয়ন্ত্রণ যেমন আছে, আমি no warnings 'experimental::smartmatch';বিবৃতিটি ব্যবহার করি ।
লিপ

43

এই ব্লগ পোস্টটি এই প্রশ্নের সেরা উত্তর আলোচনা করে।

সংক্ষিপ্তসার হিসাবে, আপনি যদি সিপিএএন মডিউলগুলি ইনস্টল করতে পারেন তবে সর্বাধিক পঠনযোগ্য সমাধানগুলি হ'ল:

any(@ingredients) eq 'flour';

অথবা

@ingredients->contains('flour');

যাইহোক, একটি আরও সাধারণ প্রতিমা হ'ল:

any { $_ eq 'flour' } @ingredients

তবে দয়া করে first()ফাংশনটি ব্যবহার করবেন না ! এটি আপনার কোডের উদ্দেশ্যটি মোটেও প্রকাশ করে না। ~~"স্মার্ট ম্যাচ" অপারেটরটি ব্যবহার করবেন না : এটি ভেঙে গেছে। এবং grep()হ্যাশ সহ সমাধানটি ব্যবহার করবেন না : তারা পুরো তালিকা দিয়ে পুনরাবৃত্তি করে।

any() এটি আপনার মান খুঁজে পাওয়ার সাথে সাথে থামবে।

আরও তথ্যের জন্য ব্লগ পোস্ট দেখুন।


8
কোন প্রয়োজনuse List::Util qw(any);List::Utilহয় কোর মডিউল
কেবলমাত্র

13

পদ্ধতি 1: গ্রেপ (যখন মানটি একটি রেজেক্স হিসাবে প্রত্যাশিত হয় তখন সাবধান হতে পারে)।

grepযদি সম্পদের দিকে তাকানো থাকে তবে ব্যবহার এড়াতে চেষ্টা করুন ।

if ( grep( /^$value$/, @badparams ) ) {
  print "found";
}

পদ্ধতি 2: লিনিয়ার অনুসন্ধান

for (@badparams) {
    if ($_ eq $value) {
       print "found";
       last;
    }
}

পদ্ধতি 3: একটি হ্যাশ ব্যবহার করুন

my %hash = map {$_ => 1} @badparams;
print "found" if (exists $hash{$value});

পদ্ধতি 4: স্মার্টমেচ

(পার্ল ৫.১০ এ যুক্ত হয়েছে, চিহ্নিত পার্ল ৫.১৮-এ পরীক্ষামূলক)।

use experimental 'smartmatch';  # for perl 5.18
print "found" if ($value ~~ @badparams);

পদ্ধতি 5: মডিউলটি ব্যবহার করুন List::MoreUtils

use List::MoreUtils qw(any);
@badparams = (1,2,3);
$value = 1;
print "found" if any {$_ == $value} @badparams;

12

@ ইকসজোর বেঞ্চমার্কটি ভেঙে গেছে - লুপে হ্যাশ তৈরির বনাম লুপে রেজিেক্সেস তৈরির ব্যবস্থা করে। স্থির সংস্করণ (প্লাস আমি যোগ করেছি List::Util::firstএবং List::MoreUtils::any):

use List::Util qw(first);
use List::MoreUtils qw(any);
use Benchmark;

my @list = ( 1..10_000 );
my $hit = 5_000;
my $hit_regex = qr/^$hit$/; # precompute regex
my %params;
$params{$_} = 1 for @list;  # precompute hash
timethese(
    100_000, {
        'any' => sub {
            die unless ( any { $hit_regex } @list );
        },
        'first' => sub {
            die unless ( first { $hit_regex } @list );
        },
        'grep' => sub {
            die unless ( grep { $hit_regex } @list );
        },
        'hash' => sub {
            die unless ( $params{$hit} );
        },
    });

এবং ফলাফল (এটি 100_000 পুনরাবৃত্তির জন্য, @ ইকসসজোর জবাবের চেয়ে দশগুণ বেশি):

Benchmark: timing 100000 iterations of any, first, grep, hash...
       any:  0 wallclock secs ( 0.67 usr +  0.00 sys =  0.67 CPU) @ 149253.73/s (n=100000)
     first:  1 wallclock secs ( 0.63 usr +  0.01 sys =  0.64 CPU) @ 156250.00/s (n=100000)
      grep: 42 wallclock secs (41.95 usr +  0.08 sys = 42.03 CPU) @ 2379.25/s (n=100000)
      hash:  0 wallclock secs ( 0.01 usr +  0.00 sys =  0.01 CPU) @ 10000000.00/s (n=100000)
            (warning: too few iterations for a reliable count)

6
আপনি যদি একাধিক উপাদানগুলির পরীক্ষা করতে চান, তবে আগে থেকে হ্যাশ তৈরি করা আপনার সময় সাশ্রয় করে। তবে আপনি যদি এটি জানতে চান যে এটিতে একটি একক উপাদান রয়েছে কিনা, তবে আপনার ইতিমধ্যে হ্যাশ নেই। সুতরাং, হ্যাশ তৈরি করা কম্পিউটিং সময়ের অংশ হওয়া উচিত। আরও নিয়মিত অভিব্যক্তির জন্য: আপনি যে প্রতিটি উপাদান সন্ধান করছেন তার জন্য আপনার একটি নতুন রেজিপ এক্স দরকার।
ফিশাইনার

1
@ ফিশিনিয়ার ট্রু, তবে আপনি যদি কেবল একটি চেকের প্রতি আগ্রহী হন, একাধিক চেক না করেন তবে অবশ্যই কোন পদ্ধতিটি দ্রুততর তা নিয়ে অবাক হওয়াও মাইক্রোপটিমাইজেশন কারণ এই মাইক্রোসেকেন্ডগুলির কোনও বিষয় নেই। আপনি যদি এই চেকটি আবারও করতে চান, হ্যাশ যাওয়ার উপায়, একবার হ্যাশ তৈরির ব্যয় কারণ তখন তা উপেক্ষা করার পক্ষে যথেষ্ট কম। উপরের মাপের মানদণ্ডগুলি কোনও সেটআপ না করে কেবল পরীক্ষার বিভিন্ন উপায় পরিমাপ করে । হ্যাঁ, এটি আপনার ব্যবহারের ক্ষেত্রে অবৈধ হতে পারে তবে আবার - আপনি যদি কেবলমাত্র একক চেক করছেন তবে আপনার এবং আপনার সাথীদের পক্ষে সবচেয়ে বেশি পাঠযোগ্য যা আপনার ব্যবহার করা উচিত।
Xaerxess

10

এটি ব্যবহারে সুবিধাজনক হলেও এটি রূপান্তর-থেকে-হ্যাশ সমাধানের জন্য অনেকগুলি পারফরম্যান্স ব্যয় করে বলে মনে হয়, যা আমার জন্য একটি সমস্যা ছিল।

#!/usr/bin/perl
use Benchmark;
my @list;
for (1..10_000) {
    push @list, $_;
}

timethese(10000, {
  'grep'    => sub {
            if ( grep(/^5000$/o, @list) ) {
                # code
            }
        },
  'hash'    => sub {
            my %params = map { $_ => 1 } @list;
            if ( exists($params{5000}) ) {
                # code
            }
        },
});

মানদণ্ড পরীক্ষার ফলাফল:

Benchmark: timing 10000 iterations of grep, hash...
          grep:  8 wallclock secs ( 7.95 usr +  0.00 sys =  7.95 CPU) @ 1257.86/s (n=10000)
          hash: 50 wallclock secs (49.68 usr +  0.01 sys = 49.69 CPU) @ 201.25/s (n=10000)

5
ব্যবহার List::Util::firstএটা iterating স্টপ হিসাবে যখন এটি একটি ম্যাচ খুঁজে বের করে দ্রুততর।
রবিআরেল

1
-1 তোমার বেঞ্চমার্ক অপূর্ণতা আছে, grepহয় উল্লেখযোগ্যভাবে যেহেতু সাবেক হে (ঢ) এবং পরেরটির হে (1) হয়, ধীর হ্যাশ তৈরি এবং লুকআপ করছেন চেয়ে। কেবলমাত্র একবারের জন্য হ্যাশ তৈরি করুন (লুপের বাইরে) এবং কেবল পদ্ধতিগুলি পরিমাপ করার জন্য পূর্ববর্তী রেজেেক্স ( আমার উত্তর দেখুন )।
Xaerxess

4
@ এক্সারেক্সেস: আমার ক্ষেত্রে আমি একটি অনুসন্ধান করতে চেয়েছিলাম , সুতরাং আমি মনে করি হ্যাশ / রেজেক্স সৃষ্টি এবং অনুসন্ধান / গ্রেপ উভয়ই গণনা করা ন্যায়সঙ্গত। এই কাজটি অনেকগুলি অনুসন্ধান করা হবে, আমার ধারণা আপনার সমাধানটি আরও ভাল।
aksel

3
আপনি যদি কেবল একটি পুনরাবৃত্তি করতে চান তবে আপনার চয়ন করা যে কোনও পদ্ধতির মধ্যে পার্থক্যটি পার্থক্য ছাড়াই, সুতরাং কোনও মানদণ্ড ভুল কারণ এটি এক্ষেত্রে একটি খারাপ মাইক্রোপটিমাইজেশন।
Xaerxess

2
রেজেক্স কেবল একবার সংকলিত হয়েছে, কারণ এতে 'ও' পতাকা রয়েছে।
Apoc

3

@ ফাইলগুলি একটি বিদ্যমান অ্যারে

my @new_values =  grep(/^2[\d].[\d][A-za-z]?/,@files);

print join("\n", @new_values);

print "\n";

এখানে 2 থেকে শুরু হওয়া ভয়েস আপনি যে কোনও নিয়মিত অভিব্যক্তি রাখতে পারেন


2

আপনি অবশ্যই এখানে একটি হ্যাশ চান। হ্যাশগুলিতে কী হিসাবে খারাপ পরামিতিগুলি রাখুন, তারপরে হ্যাশে একটি নির্দিষ্ট পরামিতি বিদ্যমান কিনা তা সিদ্ধান্ত নিন।

our %bad_params = map { $_ => 1 } qw(badparam1 badparam2 badparam3)

if ($bad_params{$new_param}) {
  print "That is a bad parameter\n";
}

আপনি যদি অ্যারে দিয়ে এটি করতে আগ্রহী হন তবে দেখুন List::Utilবা দেখুনList::MoreUtils


0

এটি করার জন্য দুটি উপায় রয়েছে are অন্যান্য পোস্টের পরামর্শ অনুসারে আপনি কোনও লুকিং টেবিলের জন্য হ্যাশটিতে মানগুলি নিক্ষেপ করতে পারেন। (আমি আরও একটি প্রতিমা যুক্ত করব।)

my %bad_param_lookup;
@bad_param_lookup{ @bad_params } = ( 1 ) x @bad_params;

তবে যদি এটি বেশিরভাগ শব্দের অক্ষরের ডেটা এবং খুব বেশি মেটা না হয় তবে আপনি এটিকে একটি রেজেক্স বিকল্পে ফেলে দিতে পারেন:

use English qw<$LIST_SEPARATOR>;

my $regex_str = do { 
    local $LIST_SEPARATOR = '|';
    "(?:@bad_params)";
 };

 # $front_delim and $back_delim being any characters that come before and after. 
 my $regex = qr/$front_delim$regex_str$back_delim/;

এই সলিউশনটি আপনি যে ধরণের "খারাপ মান" সন্ধান করছেন তার জন্য সুর করতে হবে। এবং আবার, এটি স্ট্রিংগুলির নির্দিষ্ট ধরণের জন্য সম্পূর্ণরূপে অনুপযুক্ত হতে পারে, তাই সতর্কতা অবলম্বনকারী


1
আপনি লিখতেও পারেন @bad_param_lookup{@bad_params} = ()তবে existsসদস্যপদ পরীক্ষা করার জন্য আপনার প্রয়োজন ।
গ্রেগ বেকন

-1
my @badparams = (1,2,5,7,'a','zzz');

my $badparams = join('|',@badparams);   # '|' or any other character not present in params

foreach my $par (4,5,6,7,'a','z','zzz')
{
    if ($badparams =~ /\b$par\b/)
    {
        print "$par is present\n";
    }
    else
    {
        print "$par is not present\n";
    }
}

আপনি সংখ্যাসূচক নেতৃস্থানীয় স্পেসের সামঞ্জস্যতা পরীক্ষা করতে চাইতে পারেন

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.