سؤال

لا أفهم حقًا الهدف من وظيفة الخريطة.يمكن لأي شخص أن يشرح مع أمثلة استخدامه؟

هل هناك أي فوائد أداء لاستخدام هذا بدلاً من الحلقة أم أنه مجرد سكر؟

هل كانت مفيدة؟

المحلول

في أي وقت تريد إنشاء قائمة بناءً على قائمة أخرى:

# Double all elements of a list
my @double = map { $_ * 2 } (1,2,3,4,5);
# @double = (2,4,6,8,10);

نظرًا لأنه من السهل تحويل القوائم بشكل ثنائي إلى تجزئة، إذا كنت تريد جدول تجزئة للكائنات استنادًا إلى سمة معينة:

# @user_objects is a list of objects having a unique_id() method
my %users = map { $_->unique_id() => $_ } @user_objects;
# %users = ( $id => $obj, $id => $obj, ...);

إنها أداة ذات أغراض عامة حقًا، عليك أن تبدأ في استخدامها للعثور على استخدامات جيدة في تطبيقاتك.

قد يفضل البعض التعليمات البرمجية التكرارية المطولة لأغراض سهولة القراءة، لكنني شخصيًا أجد ذلك map أكثر قابلية للقراءة.

نصائح أخرى

أولًا، إنها طريقة بسيطة لتحويل مصفوفة:بدلا من القول على سبيل المثال.

my @raw_values = (...);
my @derived_values;
for my $value (@raw_values) {
    push (@derived_values, _derived_value($value));
}

تستطيع أن تقول

my @raw_values = (...);
my @derived_values = map { _derived_value($_) } @raw_values;

كما أنه مفيد لإنشاء جدول بحث سريع:بدلا من على سبيل المثال

my $sentence = "...";
my @stopwords = (...);
my @foundstopwords;
for my $word (split(/\s+/, $sentence)) {
    for my $stopword (@stopwords) {
       if ($word eq $stopword) {
           push (@foundstopwords, $word);
       }
    }
}

بامكانك أن تقول

my $sentence = "...";
my @stopwords = (...);
my %is_stopword = map { $_ => 1 } @stopwords;
my @foundstopwords = grep { $is_stopword{$_} } split(/\s+/, $sentence);

كما أنه مفيد أيضًا إذا كنت تريد استخلاص قائمة من أخرى، ولكن لا تحتاج بشكل خاص إلى وجود متغير مؤقت يشوش المكان، على سبيل المثال.بدلا من

my %params = ( username => '...', password => '...', action => $action );
my @parampairs;
for my $param (keys %params) {
    push (@parampairs, $param . '=' . CGI::escape($params{$param}));
}
my $url = $ENV{SCRIPT_NAME} . '?' . join('&', @parampairs);

تقول أبسط من ذلك بكثير

my %params = ( username => '...', password => '...', action => $action );
my $url = $ENV{SCRIPT_NAME} . '?'
    . join('&', map { $_ . '=' . CGI::escape($params{$_}) } keys %params);

(يحرر:إصلاح "المفاتيح %params" المفقودة في السطر الأخير)

ال map يتم استخدام الوظيفة لتحويل القوائم.إنه في الأساس سكر نحوي لاستبدال أنواع معينة من for[each] حلقات.بمجرد أن تلف رأسك حوله، سترى استخداماته في كل مكان:

my @uppercase = map { uc } @lowercase;
my @hex       = map { sprintf "0x%x", $_ } @decimal;
my %hash      = map { $_ => 1 } @array;
sub join_csv { join(',', map {'"' . $_ . '"' } @_ }

أنظر أيضاً تحويل شوارتزي للاستخدام المتقدم للخريطة.

كما أنه مفيد لإنشاء تجزئات البحث:

my %is_boolean = map { $_ => 1 } qw(true false);

يعادل

my %is_boolean = ( true => 1, false => 1 );

ليس هناك الكثير من المدخرات هناك، ولكن لنفترض أنك تريد التحديد %is_US_state?

خريطة يستخدم لإنشاء قائمة عن طريق تحويل عناصر قائمة أخرى.

grep يستخدم لإنشاء قائمة عن طريق تصفية عناصر قائمة أخرى.

نوع يستخدم لإنشاء قائمة عن طريق فرز عناصر قائمة أخرى.

يتلقى كل عامل من هذه العوامل كتلة تعليمات برمجية (أو تعبيرًا) يتم استخدامها لتحويل عناصر القائمة أو تصفيتها أو مقارنتها.

ل خريطة, ، تصبح نتيجة الكتلة عنصرًا (عناصر) واحدًا (أو أكثر) في القائمة الجديدة.العنصر الحالي مستعار لـ $_.

ل grep, ، تحدد النتيجة المنطقية للكتلة ما إذا كان سيتم نسخ عنصر القائمة الأصلية إلى القائمة الجديدة.العنصر الحالي مستعار لـ $_.

ل نوع, ، تتلقى الكتلة عنصرين (الاسم المستعار لـ $a و $b) ومن المتوقع أن تُرجع واحدًا من -1 أو 0 أو 1، مما يشير إلى ما إذا كان $a أكبر أو يساوي أو أقل من $b.

ال تحويل شوارتزي يستخدم عوامل التشغيل هذه للتخزين المؤقت للقيم (الخصائص) بكفاءة لاستخدامها في فرز القائمة، خاصة عندما تكون تكلفة حساب هذه الخصائص غير تافهة.

إنه يعمل عن طريق إنشاء مصفوفة وسيطة تحتوي على مراجع مصفوفة عناصر مع العنصر الأصلي والقيمة المحسوبة التي نريد الفرز بها.يتم تمرير هذه المصفوفة للفرز، والتي تقارن القيم المحسوبة بالفعل، وإنشاء مصفوفة متوسطة أخرى (يتم فرز هذه المصفوفة) والتي بدورها يتم تمريرها إلى خريطة أخرى والتي تتخلص من القيم المخزنة مؤقتًا، وبالتالي استعادة المصفوفة إلى عناصر القائمة الأولية الخاصة بها (ولكن بالترتيب المطلوب الآن).

مثال (إنشاء قائمة بالملفات الموجودة في الدليل الحالي مرتبة حسب وقت آخر تعديل لها):

@file_list = glob('*');
@file_modify_times = map { [ $_, (stat($_))[8] ] } @file_list;
@files_sorted_by_mtime = sort { $a->[1] <=> $b->[1] } @file_modify_times;
@sorted_files = map { $_->[0] } @files_sorted_by_mtime;

من خلال ربط العوامل معًا، لا يلزم الإعلان عن المتغيرات للمصفوفات الوسيطة؛

@sorted_files = map { $_->[0] } sort { $a->[1] <=> $b->[1] } map { [ $_, (stat($_))[8] ] } glob('*');

يمكنك أيضًا تصفية القائمة قبل الفرز عن طريق إدراج ملف grep (إذا كنت تريد التصفية على نفس القيمة المخزنة مؤقتًا):

مثال (قائمة الملفات التي تم تعديلها خلال 24 ساعة الأخيرة مرتبة حسب وقت التعديل الأخير):

    @sorted_files = map { $_->[0] } sort { $a->[1] <=> $b->[1] } grep { $_->[1] > (time - 24 * 3600 } map { [ $_, (stat($_))[8] ] } glob('*');

تقوم وظيفة الخريطة بتشغيل تعبير على كل عنصر في القائمة، وتقوم بإرجاع نتائج القائمة.لنفترض أن لدي القائمة التالية

@names = ("andrew", "bob", "carol" );

وأردت تكبير الحرف الأول من كل من هذه الأسماء.يمكنني تكرارها واستدعاء ucfirst لكل عنصر، أو يمكنني فقط القيام بما يلي

@names = map (ucfirst, @names);

وظيفة الخريطة هي فكرة من نموذج البرمجة الوظيفية.في البرمجة الوظيفية، تعد الوظائف كائنات من الدرجة الأولى، مما يعني أنه يمكن تمريرها كوسيطات إلى وظائف أخرى.الخريطة هي مثال بسيط ولكنه مفيد جدًا على ذلك.إنها تأخذ وظيفة كوسيطاتها (دعنا نسميها f) وقائمة l. f يجب أن تكون دالة تأخذ وسيطة واحدة، وتنطبق الخريطة ببساطة f لكل عنصر من عناصر القائمة l. f يمكنك فعل كل ما تريد القيام به لكل عنصر:أضف واحدًا إلى كل عنصر، أو قم بتربيع كل عنصر، أو اكتب كل عنصر في قاعدة بيانات، أو افتح نافذة متصفح الويب لكل عنصر، والذي يصادف أنه عنوان URL صالح.

ميزة الاستخدام map هو أنه يلخص بشكل جيد التكرار على عناصر القائمة.كل ما عليك فعله هو أن تقول "افعل". f لكل عنصر، والأمر متروك ل map لتقرر أفضل السبل للقيام بذلك.على سبيل المثال map يمكن تنفيذه لتقسيم عمله بين عدة سلاسل، وسيكون شفافًا تمامًا للمتصل.

لاحظ أن map ليست خاصة بـ Perl على الإطلاق.إنها تقنية قياسية تستخدمها اللغات الوظيفية.ويمكن تنفيذه أيضًا في لغة C باستخدام مؤشرات الوظائف، أو في لغة C++ باستخدام "الكائنات الوظيفية".

"فقط السكر" قاسية.تذكر أن الحلقة هي مجرد سكر - يمكن لـ if's وgoto القيام بكل ما تفعله إنشاءات الحلقة وأكثر من ذلك.

الخريطة هي وظيفة عالية المستوى بما يكفي لمساعدتك على إجراء عمليات أكثر تعقيدًا في رأسك، حتى تتمكن من برمجة وتصحيح المشكلات الأكبر.

لإعادة صياغة "برمجة Perl الفعالة" من قِبل Hall & Schwartz ، يمكن إساءة استخدام MAP ، لكنني أعتقد أنه من الأفضل استخدامها لإنشاء قائمة جديدة من قائمة موجودة.

أنشئ قائمة بالمربعات 3،2، و1:

@numbers = (3,2,1);
@squares = map { $_ ** 2 } @numbers;

إنشاء كلمة المرور:

$ perl -E'say map {chr(32 + 95 * rand)} 1..16'
# -> j'k=$^o7\l'yi28G

يمكنك استخدام الخريطة لتحويل قائمة وتعيين النتائج إلى قائمة أخرى، و grep لتصفية قائمة وتعيين النتائج إلى قائمة أخرى.يمكن أن تكون القائمة "الأخرى" هي نفس المتغير مثل القائمة التي تقوم بتحويلها/تصفيتها.

my @array = ( 1..5 );
@array = map { $_+5 } @array;
print "@array\n";
@array = grep { $_ < 7 } @array;
print "@array\n";

يتم استخدامه في أي وقت ترغب فيه في إنشاء قائمة جديدة من قائمة موجودة.

على سبيل المثال، يمكنك تعيين دالة تحليل على قائمة سلاسل لتحويلها إلى أعداد صحيحة.

يسمح لك بتحويل القائمة كملف تعبير وليس في صياغات.تخيل تجزئة الجنود المحددة على النحو التالي:

{ name          => 'John Smith'
, rank          => 'Lieutenant'
, serial_number => '382-293937-20'
};

ثم يمكنك العمل على قائمة الأسماء بشكل منفصل.

على سبيل المثال،

map { $_->{name} } values %soldiers

هو تعبير.يمكن أن ينتقل إلى أي مكان يُسمح فيه بالتعبير - باستثناء أنه لا يمكنك تعيينه.

${[ sort map { $_->{name} } values %soldiers ]}[-1]

فهرسة المصفوفة، مع أخذ الحد الأقصى.

my %soldiers_by_sn = map { $->{serial_number} => $_ } values %soldiers;

أجد أن إحدى مزايا التعبيرات التشغيلية هي أنها تقلل الأخطاء التي تأتي من المتغيرات المؤقتة.

إذا كان السيد.يريد McCoy تصفية جميع Hatfields للنظر فيها، ويمكنك إضافة هذا الاختيار بأقل قدر من الترميز.

my %soldiers_by_sn 
    = map  { $->{serial_number}, $_ } 
      grep { $_->{name} !~ m/Hatfield$/ } 
      values %soldiers
      ;

يمكنني الاستمرار في تسلسل هذه التعبيرات بحيث إذا كان تفاعلي مع هذه البيانات يجب أن يصل إلى العمق لغرض معين، فلن أضطر إلى كتابة الكثير من التعليمات البرمجية التي تتظاهر بأنني سأفعل الكثير.

كما قال آخرون، تقوم الخريطة بإنشاء قوائم من القوائم.فكر في "ربط" محتويات قائمة ما بقائمة أخرى.إليك بعض التعليمات البرمجية من برنامج CGI للحصول على قائمة بأرقام براءات الاختراع وطباعة الارتباطات التشعبية لطلبات براءات الاختراع:

my @patents = ('7,120,721', '6,809,505', '7,194,673');
print join(", ", map { "<a href=\"http://patft.uspto.gov/netacgi/nph-Parser?Sect1=PTO1&Sect2=HITOFF&d=PALL&p=1&u=/netahtml/srchnum.htm&r=0&f=S&l=50&TERM1=$_\">$_</a>" } @patents);

كما قال آخرون، الخريطة مفيدة للغاية لتحويل القائمة.ما لم يتم ذكره هو الفرق بين الخريطة و"المعادل" للحلقة.

أحد الاختلافات هو أن for لا يعمل بشكل جيد مع التعبير الذي يعدل القائمة التي يتم تكرارها.ينتهي أحدهما والآخر لا:

perl -e '@x=("x"); map { push @x, $_ } @x'
perl -e '@x=("x"); push @x, $_ for @x'

هناك اختلاف بسيط آخر وهو أن سياق يوجد داخل كتلة الخريطة سياق قائمة، لكن حلقة for تضفي سياقًا فارغًا.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top