質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

90.23%

array_mapとarray_walkの違い

解決済

回答 3

投稿 編集

  • 評価
  • クリップ 2
  • VIEW 3,791

SugiuraY

score 231

お世話になります。

もろもろ調べたのですが、なかなか納得ができません。
掲題の配列の要素をそれぞれ2倍にする関数ですが

1) array_walkはもとの配列の変数$arrayのままで、function適用後の値(2倍かけた値)が得られ、一方array_mapは
$array2に格納して出力しなければfunction適用後の値(2倍かけた値)が得られないのは、walkは破壊的メソッドでmapは非破壊的メソッドであるからという理解であっていますでしょうか?

2)なぜ、コールバック関数の中身が$item= $item*2;とreturn $item*2;と違いが生じるのかがそれぞれの関数の仕様からいまいち理解ができません。なんとなくmapのほうが理解できるのですが、walkはマニュアルを見ると返り値として「成功した場合に TRUE を、失敗した場合に FALSE を返します。」と説明がされています。この違いからくるのでしょうか?

3)2)に関連してですが、そもそも成功と失敗とは何を指しているのでしょうか?

4)2)に関連してですが、このコールバック関数でtrueやfalseを返すことに全く意味がないように思えるのですが。。配列の値やkeyに関数を適用する意図があって作られたwalkやmapであると理解しているのですが、まったくarray_walkの意味がないような気がしてならないのですが、どのようなケースを想定してる関数(これでなくては処理できない?)なのでしょうか?
もし具体的な例とかがあれば。。

なにとぞ、宜しくお願い申し上げます。

walk

<?php
$array=array(5,10);
function twice (&$item)
{
$item= $item*2;
}
array_walk($array,'twice');

var_dump($array);
?>
map

$array=array(5,10);
function twice ($item)
{
return $item*2;
}

$array2=array_map('twice',$array);

var_dump($array2);
?>
  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 3

checkベストアンサー

+1

array_map、 array_walk

array_map — 指定した配列の要素にコールバック関数を適用する
array_walk — 配列の全ての要素にユーザー定義の関数を適用する

違いが全然分からない・・・・これは公式が言葉足らずですね。
引数や戻り値のUsage的なアレを見ればarray_walkは破壊メソッドなのはかろうじてわかりますが・・・・

そもそもmapという名称は地図を連想するかと思いますが、
工場でプレス加工して一度に大量の製品を作る事もmapと呼ばれるそうです。
そこから転じて、配列の中身に同じ処理を加えて加工後の値を一気に取り出す事を指すそうです。

mapは関数型プログラミングのList操作に属するもので、
高階関数 map等のワードでググると関数型プログラミングでは一般的に使用される関数として紹介されています。
特徴は大体こんな感じ

  • 非破壊メソッドである
  • 関数を引数として要求する
  • 戻り値に加工後の配列を返す
  • 加工前と加工後の配列は要素数は一致する

下記がJavaScriptでの実装の一例です。
PHPのarray_mapとは少し違いますが、Arrayに内蔵されているmapメソッドを利用して実現しています。

var twice = function (it) { return it * 2; };
var arr = [1, 2, 3].map(twice);
console.log(arr);
// [2, 4, 6]

逆にwalkは何者なんでしょうね?
foreachが言語構造として実装されてしまっているので要らない関数にしか見えません。
(一応array_walk_recursiveまでいけば役に立つと思うのですが…)


「追記部分」

レスを読んでいると下記の記事がお役に立ちそうなので、共有します。
array_mapにありがとう、さよなら
部分適用ってなんだ

コールバック関数による配列操作はそもそもPHPに必要ありません。
関数型プログラミングをやるにはPHPは不向きだと私は思っています。
foreachという万能言語構造がありますから、やりたいことの大多数は高階関数がなくてもできます。

array_mapとforeach、array_walk等を無理に混ぜると、コードが読みづらくなる可能性は高いです。
コードの見通しを良くする為に関数型プログラミングの書き方で統一するくらいなら、
最初からScalaのような関数型言語を使えば良いじゃないかと考えます。

ChatWorkも最初はPHPで、後に全サービスをScalaで書き直したそうです。
ただし、将来PHPもJavaからスピンオフしたScalaみたいな言語が生まれるかもしれませんね。

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2016/11/09 16:40

    ご回答いただき、有難うございます!
    そうなんですよ~、、しかもforeachのほうが処理も早く、、、、一体配列の中をwalkして破壊だけして去っていくこの関数の存在意義を見出せません。recursiveは確かにお世話になっております。

    キャンセル

0

難しい質問ですね。。。

1

array_walkは破壊的メソッドでarray_mapは非破壊的メソッドの理解で良いと思います。

2

array_walkは破壊的という事で内部のコールバック関数の中で与えられた引数の配列のアドレスそのものに操作をしているのだろうと思います。(思いますというのは実際のphpのソース読みかけましたが、時間かかりそうなのでやめました、あとで参考にURL載せておきます)質問者様のソースもそういうコールバックになってますよね?上書きっぽい処理に
対して
array_mapは非破壊的なのでコールバックの引数のアドレスそのものではなくもとの値は変えずに処理してますよね?

3

これが一番難しい、、何をもって成功・失敗にするか、正確に何を成功・何を失敗としてあつかっているかはソース見ないとわかりません。。。

https://github.com/php/php-src

https://github.com/php/php-src/blob/master/ext/standard/array.c
の中にphp_walkのソースがありますが、マクロまみれで読むのに時間かかりそうでやめましたが気になるなら是非

4

array_walkの操作はほぼforeachで実現可能です。

foreach($array as $key=>$val)
    $array[$key] = $val * 2;


ただし、こんな資料がありました。
https://www.reddit.com/r/PHP/comments/1uuc34/quick_test_to_see_if_array_walk_is_better_than/
とか
https://eval.in/87941
https://eval.in/87942
とか

foreachの方が早いですね。。。。
特に優位性見出せないです。

追記

いつのまにかarray_walkとforeach比較の回答になってました、重要な点

配列の値やkeyに関数を適用する意図があって作られたwalkやmapであると理解しているのですが、array_walkの意味がないような気がしてならないのですが、どのようなケースを想定してる関数(これでなくては処理できない?)なのでしょうか? 

に関しては大きな違いは1にある通り元の配列も残すか、残さないかの違いです。これは大きな違いで配列の各要素になんらかの処理をしたい(ここまでは同じ)が元の配列も後でつかうので残しておかなくてはならないならmap、上書き上書きで後ろを振り向かなくていいならwalkといったところでしょうか。

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2016/11/09 16:31

    ご親切にご回答を頂き、誠に有難うございます。あまりのご丁寧さに涙です。
    一点だけ気になったのですが、
    >array_walkの操作はほぼforeachで実現可能です。

    と仰って頂き、良くこのお話も聞くのですが、array_mapも、各配列要素や添字に定義関数を適用できるという意味では、foreachで代用できるきがするのですが。。
    もちろん、破壊的メソッドという点では、全く結果は異なるとおもいます。

    キャンセル

  • 2016/11/09 16:41

    はい、array_mapもforeachで代用できると思います。これを書いてしまうと反対意見とかもでそうですが、phpの標準関数すべてが有用な関数で、本当に必要な関数とは思えないです。私個人的には今回の質問の操作をする場合まずarray_map、array_walk関数を使わないです。というより私自身ほとんどこれらの関数使った場面おもいだせません。

    キャンセル

  • 2016/11/09 16:44

    コメントありがとうございます。
    ある意味で一番明解なご回答だと思います。便利なのか不便なのか、マニュアル見ながら眉間にしわを寄せていたので、あまり微妙な組込関数には首を突っ込まないほうが良いかもしれません。。

    キャンセル

0

間違ったコメントを修正さました。

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 90.23%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

同じタグがついた質問を見る