2010-08-07 11 views
309

के बीच अंतर array_map, array_walk और array_filter के बीच का अंतर क्या है। दस्तावेज़ीकरण से मैं क्या देख सकता था कि आप आपूर्ति किए गए सरणी पर कार्रवाई करने के लिए कॉलबैक फ़ंक्शन पास कर सकते हैं। लेकिन मुझे उनके बीच कोई विशेष अंतर नहीं दिख रहा है।array_map, array_walk और array_filter

क्या वे वही काम करते हैं?
क्या वे एक दूसरे के लिए इस्तेमाल किया जा सकता है?

यदि वे अलग हैं तो मैं उदाहरण के उदाहरण के साथ आपकी मदद की सराहना करता हूं।

+0

यह array_reduce() के माध्यम से नामित सरणी प्रसंस्करण के लिए एक अच्छी चाल है। यदि आप array_map, array_walk, और array_filter की जांच कर रहे हैं तो पढ़ने के लायक होंगे। http://stackoverflow.com/questions/11563119/array-map-callback-access-to-associative-array-key-and-value/15303635#15303635 –

उत्तर

454
  • array_map पर कोई संपार्श्विक प्रभाव नहीं है जबकि array_walk कर सकते हैं; विशेष रूप से, array_map अपने तर्क कभी नहीं बदलता है।
  • array_map सरणी कुंजी, array_walk कैन के साथ काम नहीं कर सकता है।
  • array_map एक सरणी देता है, array_walk केवल true/false देता है। इसलिए, यदि आप एक सरणी को घुमाने के परिणामस्वरूप कोई सरणी नहीं बनाना चाहते हैं, तो आपको array_walk का उपयोग करना चाहिए।
  • array_map भी मनमाने ढंग से सरणी प्राप्त कर सकते हैं, जबकि array_walk केवल एक पर चल रहा है।
  • array_walk कॉलबैक पास करने के लिए एक अतिरिक्त मनमानी पैरामीटर प्राप्त कर सकते हैं। यह PHP 5.3 के बाद से अधिकतर अप्रासंगिक है (जब anonymous functions पेश किए गए थे)।
  • array_map/array_walk के परिणामस्वरूप सरणी में तर्कों के समान तत्व हैं; array_filter फ़िल्टरिंग फ़ंक्शन के अनुसार सरणी के तत्वों का केवल एक सबसेट चुनता है। यह चाबियाँ सुरक्षित रखता है।

उदाहरण:

<pre> 
<?php 

$origarray1 = array(2.4, 2.6, 3.5); 
$origarray2 = array(2.4, 2.6, 3.5); 

print_r(array_map('floor', $origarray1)); // $origarray1 stays the same 

// changes $origarray2 
array_walk($origarray2, function (&$v, $k) { $v = floor($v); }); 
print_r($origarray2); 

// this is a more proper use of array_walk 
array_walk($origarray1, function ($v, $k) { echo "$k => $v", "\n"; }); 

// array_map accepts several arrays 
print_r(
    array_map(function ($a, $b) { return $a * $b; }, $origarray1, $origarray2) 
); 

// select only elements that are > 2.5 
print_r(
    array_filter($origarray1, function ($a) { return $a > 2.5; }) 
); 

?> 
</pre> 

परिणाम:

Array 
(
    [0] => 2 
    [1] => 2 
    [2] => 3 
) 
Array 
(
    [0] => 2 
    [1] => 2 
    [2] => 3 
) 
0 => 2.4 
1 => 2.6 
2 => 3.5 
Array 
(
    [0] => 4.8 
    [1] => 5.2 
    [2] => 10.5 
) 
Array 
(
    [1] => 2.6 
    [2] => 3.5 
) 
+0

क्या आप उन्हें उदाहरण के साथ दिखा सकते हैं? –

+0

ग्रेट, धन्यवाद :) –

+3

PHP मैनुअल कहता है: "array_walk(): केवल सरणी के मान संभावित रूप से बदला जा सकता है;" – feeela

35
प्रलेखन से

,

bool array_walk (सरणी & $ सरणी, कॉलबैक $ funcname [, मिश्रित $ userdata ]) <-वापसी बूल

array_walk एक सरणी और एक समारोह F लेता है और F(x) साथ हर तत्व एक्स की जगह यह संशोधित करता है।

सरणी array_map (कॉलबैक $ कॉलबैक, सरणी $ arr1 [, सरणी $ ...]) < -return सरणी

array_map में संशोधित करने की है कि बजाय को छोड़कर बिल्कुल वही चीज़ करता है - यह बदले गए तत्वों के साथ एक नई सरणी वापस कर देगा।

सरणी array_filter (सरणी $ इनपुट [, कॉलबैक $ कॉलबैक]) < -return सरणी

समारोह F साथ array_filter, बजाय तत्वों बदलने की, किसी भी तत्व है जिसके लिए F(x) नहीं है निकाल देंगे सच

+2

क्या आप उन्हें एक उदाहरण के साथ दिखा सकते हैं? –

+3

यह मेरे लिए +1 का सबसे अच्छा जवाब है। – deem

+0

यह पता नहीं लगा सका कि मेरे सरणी मान क्यों गायब हो गए। प्रलेखन को देखते हुए मैंने मान लिया कि 'array_walk' ने' array_map' जैसे सरणी को वापस कर दिया है और यह अनुमान लगाया है कि समस्या मेरे फ़ंक्शन में थी। तब तक एहसास नहीं हुआ जब तक मैंने यह देखा कि वापसी का प्रकार बुलियन है। –

84

mapping का विचार डेटा की सरणी के लिए एक फ़ंक्शन कार्यात्मक प्रोग्रामिंग से आता है। आपको array_map के बारे में foreach लूप के बारे में नहीं सोचना चाहिए जो सरणी के प्रत्येक तत्व पर एक फ़ंक्शन को कॉल करता है (भले ही यह कार्यान्वित किया गया हो)। इसे स्वतंत्र रूप से सरणी में प्रत्येक तत्व को फ़ंक्शन को लागू करने के रूप में सोचा जाना चाहिए।

सिद्धांत रूप में फ़ंक्शन मैपिंग जैसी चीजें समानांतर में की जा सकती हैं क्योंकि डेटा पर लागू होने वाले फ़ंक्शन को केवल डेटा को प्रभावित करना चाहिए, न कि वैश्विक स्थिति। ऐसा इसलिए है क्योंकि array_map आइटम में फ़ंक्शन को लागू करने के लिए कोई भी ऑर्डर चुन सकता है (भले ही PHP में यह नहीं है)।

array_walk दूसरी ओर यह डेटा के सरणी को संभालने के लिए बिल्कुल विपरीत विपरीत दृष्टिकोण है। प्रत्येक आइटम को अलग से संभालने के बजाय, यह एक राज्य (&$userdata) का उपयोग करता है और आइटम को जगह में संपादित कर सकता है (अधिक फ़ोरैच लूप की तरह)। प्रत्येक बार जब किसी आइटम में $funcname लागू होता है, तो यह प्रोग्राम की वैश्विक स्थिति बदल सकता है और इसके लिए वस्तुओं को संसाधित करने के लिए सही आवश्यकता होती है।

पीएचपी भूमि में वापस, array_map और array_walk लगभग समान छोड़कर array_walk आप डेटा के यात्रा पर अधिक नियंत्रण देता है और सामान्य रूप से एक नया "बदला" सरणी बनाम वापस लौटने वाले यथा-स्थान डेटा "परिवर्तन" करने के लिए प्रयोग किया जाता है।

array_filter वास्तव में array_walk (या array_reduce) का एक एप्लिकेशन है और यह सुविधा के लिए प्रदान की गई कम या कम है।

array_filter() डेटा को फ़िल्टर कर देता, एक परिणाम के एक के रूप में उत्पादन:

+2

आपके गुरु के अनुच्छेद अंतर्दृष्टि के लिए –

+3

+1 होने के लिए +1 "सिद्धांत में फ़ंक्शन मैपिंग जैसी चीजें समानांतर में की जा सकती हैं क्योंकि डेटा पर लागू होने वाले फ़ंक्शन को केवल डेटा को प्रभावित करना चाहिए, न कि वैश्विक स्थिति।" हमारे लिए समांतर प्रोग्रामर, यह ध्यान में रखना एक उपयोगी बात है। – etherice

+0

क्या आप समझा सकते हैं कि 'array_wilter()' 'array_walk()' का उपयोग करके कैसे लागू किया जा सकता है? – pfrenssen

1

निम्नलिखित संशोधन अधिक स्पष्ट रूप से, पीएचपी के array_filer() चित्रित करने के लिए array_map(), और array_walk(), जो सभी के कार्यात्मक प्रोग्रामिंग से ही शुरू करना चाहता है नई सरणी पकड़े पूर्व सरणी के केवल इच्छित आइटम, इस प्रकार है:

<?php 
$array = array(1, "apples",2, "oranges",3, "plums"); 

$filtered = array_filter($array, "ctype_alpha"); 
var_dump($filtered); 
?> 

लाइव कोड here

सभी संख्यात्मक मान $ सरणी से फ़िल्टर कर दिया, $ फल का केवल प्रकार के साथ फ़िल्टर्ड छोड़कर।

array_map() भी एक नई सरणी बनाता है लेकिन array_filter() के विपरीत जिसके परिणामस्वरूप सरणी, इनपुट $ फ़िल्टर कर दी जाती है, लेकिन बदले हुए मूल्यों के साथ हर तत्व शामिल प्रत्येक तत्व के लिए एक कॉलबैक लागू करने के कारण, इस प्रकार है:

<?php 

$nu = array_map("strtoupper", $filtered); 
var_dump($nu); 
?> 

लाइव कोड here

इस मामले में कोड में निर्मित strtoupper() एक कॉलबैक का उपयोग कर, लेकिन एक उपयोगकर्ता परिभाषित समारोह लागू होता है एक और व्यवहार्य विकल्प भी है। कॉलबैक फ़िल्टर किए गए प्रत्येक आइटम पर लागू होता है और इस प्रकार $ nu engenders जिनके तत्वों में अपरकेस मान होते हैं।

अगले स्निपेट में, सरणी चलना() $ nu ट्रैवर्स करता है और संदर्भ तत्व '&' के विपरीत प्रत्येक तत्व में परिवर्तन करता है। परिवर्तन अतिरिक्त सरणी बनाने के बिना होते हैं। प्रत्येक तत्व का मान अपनी कुंजी, श्रेणी और मान निर्दिष्ट करने वाली अधिक जानकारीपूर्ण स्ट्रिंग में जगह में बदल जाता है।

<?php 

$f = function(&$item,$key,$prefix) { 
    $item = "$key: $prefix: $item"; 
}; 
array_walk($nu, $f,"fruit"); 
var_dump($nu);  
?>  

देखें demo

नोट:, array_walk के संबंध में कॉलबैक फ़ंक्शन() दो पैरामीटर जो स्वचालित रूप से एक तत्व के मूल्य और इसके प्रमुख और इसी क्रम में अधिग्रहण करेगा लेता भी जब array_walk द्वारा लाया()। (here और देखें)।

+1

ध्यान दें कि 'lambda' और '$ कॉलबैक' फ़ंक्शंस केवल मौजूदा कार्यों के ईटा-विस्तार हैं, और इसलिए पूरी तरह से अनावश्यक हैं। आप अंतर्निहित फ़ंक्शन को पास करके (नाम का नाम) प्राप्त कर सकते हैं: '$ filtered = array_filter ($ array, 'ctype_alpha');' और '$ nu = array_map ('strtoupper', $ फ़िल्टर किया गया);' – Warbo

+0

धन्यवाद आप - अच्छा पकड़ो! – slevy1

15

अन्य उत्तरों array_walk (इन-प्लेस संशोधन) और array_map (वापसी संशोधित प्रतिलिपि) के बीच अंतर का प्रदर्शन करते हैं। हालांकि, वे वास्तव में array_reduce का उल्लेख नहीं करते हैं, जो array_map और array_filter को समझने का एक रोशनी तरीका है।

array_reduce(array('a', 'b', 'c', 'd'), 
      'my_function', 
      $accumulator) 

सरणी के तत्वों को देखते हुए समारोह का उपयोग कर एक समय में संचायक एक के साथ संयुक्त कर रहे हैं,:

array_reduce समारोह एक सरणी, एक दो तर्क समारोह और एक 'संचायक', इस तरह से लेता है। , आप छोरों के संदर्भ में सोचने के लिए पसंद करते हैं

my_function(
    my_function(
    my_function(
     my_function(
     $accumulator, 
     'a'), 
     'b'), 
    'c'), 
    'd') 

यह निम्न कार्य की तरह है (मैं वास्तव में एक वापस आने के रूप में इस का उपयोग किया है जब array_reduce नहीं था: ऊपर कॉल का परिणाम यह कर के रूप में ही है उपलब्ध): हम एक यात्रा के माध्यम से परिणाम जमा करने के लिए उपयोग कर सकते हैं:

function array_reduce($array, $function, $accumulator) { 
    foreach ($array as $element) { 
    $accumulator = $function($accumulator, $element); 
    } 
    return $accumulator; 
} 

यह पाशन संस्करण यह स्पष्ट कारण है कि मैं तीसरा तर्क एक 'संचायक' नामक गया है बनाता है।

तो array_map और array_filter के साथ इसका क्या संबंध है? यह पता चला है कि वे दोनों एक विशेष प्रकार की array_reduce हैं। हम उन्हें इस तरह लागू कर सकते हैं:

array_map($function, $array) === array_reduce($array, $MAP, array()) 
array_filter($array, $function) === array_reduce($array, $FILTER, array()) 

तथ्य यह है कि array_map पर ध्यान न दें और एक अलग क्रम में अपने तर्क ले array_filter; यह सिर्फ PHP का एक और quirk है। महत्वपूर्ण बात यह है कि दाएं हाथ की तरफ उन कार्यों को छोड़कर समान है जिन्हें मैंने $ एमएपी और $ फ़िल्टर कहा है। तो, वे क्या दिखते हैं?

$MAP = function($accumulator, $element) { 
    $accumulator[] = $function($element); 
    return $accumulator; 
}; 

$FILTER = function($accumulator, $element) { 
    if ($function($element)) $accumulator[] = $element; 
    return $accumulator; 
}; 

जैसा कि आप देख सकते हैं, दोनों कार्य $ accumulator में लेते हैं और इसे फिर से वापस कर देते हैं। इन कार्यों में दो मतभेद हैं:

  • $ एमएपी हमेशा $ accumulator में संलग्न होगा, लेकिन $ FILTER केवल तभी होगा यदि $ फ़ंक्शन ($ तत्व) सत्य है।
  • $ फ़िल्टर मूल तत्व जोड़ता है, लेकिन $ एमएपी $ फ़ंक्शन ($ तत्व) जोड़ता है।

ध्यान दें कि यह बेकार मामूली से बहुत दूर है; हम अपने एल्गोरिदम को और अधिक कुशल बनाने के लिए इसका उपयोग कर सकते हैं!

हम अक्सर इन दो उदाहरणों की तरह कोड देख सकते हैं:

// Transform the valid inputs 
array_map('transform', array_filter($inputs, 'valid')) 

// Get all numeric IDs 
array_filter(array_map('get_id', $inputs), 'is_numeric') 

array_map का उपयोग करना और छोरों के बजाय array_filter बनाता है इन उदाहरणों काफी अच्छा लग रही है। हालांकि, यह बहुत अक्षम हो सकता है यदि $ इनपुट बड़ा है, क्योंकि पहला कॉल (मानचित्र या फ़िल्टर) $ इनपुट को पार करेगा और एक मध्यवर्ती सरणी का निर्माण करेगा। यह इंटरमीडिएट सरणी सीधे दूसरी कॉल में पारित की जाती है, जो पूरी चीज को फिर से पार कर लेगी, फिर इंटरमीडिएट सरणी को कचरा इकट्ठा करने की आवश्यकता होगी।

हम इस इंटरमीडिएट सरणी से इस तथ्य का शोषण कर सकते हैं कि array_map और array_filter array_reduce के दोनों उदाहरण हैं।

// Transform valid inputs 
array_reduce($inputs, 
      function($accumulator, $element) { 
       if (valid($element)) $accumulator[] = transform($element); 
       return $accumulator; 
      }, 
      array()) 

// Get all numeric IDs 
array_reduce($inputs, 
      function($accumulator, $element) { 
       $id = get_id($element); 
       if (is_numeric($id)) $accumulator[] = $id; 
       return $accumulator; 
      }, 
      array()) 

नोट:: उन्हें संयोजन से, हम केवल हर उदाहरण में एक बार $ आदानों पार करने के लिए है array_map मेरे कार्यान्वयन और इसके बाद के संस्करण array_filter वास्तव में PHP के की तरह व्यवहार नहीं किया जाएगा, के बाद से मेरी array_map केवल एक में एक सरणी संभाल कर सकते हैं समय और मेरा array_filter "खाली" का उपयोग अपने डिफ़ॉल्ट $ फ़ंक्शन के रूप में नहीं करेगा। इसके अलावा, न तो कुंजी को सुरक्षित रखेगा।

उन्हें PHP की तरह व्यवहार करना मुश्किल नहीं है, लेकिन मुझे लगा कि ये जटिलताओं को मूल विचार को स्थानांतरित करना कठिन होगा।

संबंधित मुद्दे