usortのユーザー定義比較関数の説明について

このQ&Aのポイント
  • usortのユーザー定義比較関数についての説明が不明確で理解が難しいです。
  • 説明として示されている例と、実際の使用例が異なるため、混乱しています。
  • ユーザー定義比較関数の使い方や動作の詳細について詳しく説明してほしいです。
回答を見る
  • ベストアンサー

usort のユーザー定義比較関数の説明について

PHPマニュアルにあるusortの説明がうまく理解できなくて悩んでいます。 そこでは、パラメータとなる比較関数について次のように書かれています。 「比較関数は、最初の引数と二番目の引数の比較結果を返します。最初の引数のほうが二番目の引数より大きい場合は正の数を、二番目の引数と等しい場合はゼロを、そして二番目の引数より小さい場合は負の数を返す必要があります。」 http://php.net/manual/ja/function.usort.php 「usort() の例」として提示されているのは以下です。 function cmp($a, $b) { if ($a == $b) { return 0; } return ($a < $b) ? -1 : 1; } $a = array(3, 2, 5, 6, 1); usort($a, "cmp"); この例のユーザー定義の比較関数cmpは、前述の説明の通りに書かれているので理解できます。 しかし、ユーザーページの投稿にもありますが、($a > $b) としたり、($a < $b) ? 1 : -1 のように返り 値を変えて降順(逆順)にソートするという使い方を普通に見かけます。 これは、「最初の引数のほうが二番目の引数より大きい場合は正の数を(……)二番目の引数より小さい場合は負の数を返す必要があ」るという説明とは矛盾しています。 「必要」とまで書いているのでかなり強い指示だと思います。英語版でも「must」となっているので翻訳上の問題はなさそうです。 また、「配列のソート」ページによるとソート順は「ユーザー定義」とあり、件の比較関数次第ということになっています。 http://www.php.net/manual/ja/array.sorting.php ということは、逆順であれ自然順であれ可能だとこれは示唆しているのだと思うのですが、やはり説明部分との矛盾が気になります。 ……どう捉えたらよいのでしょうか?

  • PHP
  • 回答数5
  • ありがとう数6

質問者が選んだベストアンサー

  • ベストアンサー
noname#244856
noname#244856
回答No.3

「最初の引数のほうが二番目の引数より大きい場合は正の数を(……)二番目の引数より小さい場合は負の数を返す必要がある」 ↓ 「配列の中から任意に2要素$a,$b(但し$aの方がかならず左にある)を取り出したとき、$aと$bを入れ替える必要があれば正の数を、入れ替える必要が無ければ負の数を返す必要がある」 と置き換えて考えてください。 (実際には等しい場合は0を返したほうがソートの効率がよくなると思われます) こちらのC言語のバブルソートのプログラムをご覧ください。 http://www1.cts.ne.jp/~clab/hsample/Sort/Sort1.html if (x[j - 1] > x[j]) { /* 前の要素の方が大きかったら */ この行を if (cmp_function(a, b)) { /* 前の要素の方が大きかったら */ に置き換えるのがusort関数と考えると分かりやすいですかね? (実際にPHPが行っているのはバブルソートではなく、クイックソート・マージソートなどの併用ソートですが)

salyuun
質問者

お礼

分かりやすい例をありがとうございます。文字通りに捉えすぎたようです。理解できました。

その他の回答 (4)

  • mpro-gram
  • ベストアンサー率74% (170/228)
回答No.5

データの大小と、順列番号の大小は別 なのですが、質問者さんの引っかかってる「must」については、日本語の語順に惑わされてるようです。 must return an integer は、返値は、Integer型で返す必要があるの意味。 引数比較については considered to be respectively なので、どっちを大きい(順列の後方)と考えるかによって返値を調整しろということ。「必ず大きい方」ではない。 日本語にすると語順的にどこに「必要」がかかってるか解りにくいのが欠点ではある。ていうか「整数」が抜けてるせいか?

salyuun
質問者

お礼

ありがとうございます。理解できました。

  • NoOkWave
  • ベストアンサー率50% (1/2)
回答No.4

一番目の引数の値は、2、 二番目の引数の値は、5 だったとして、 2と5、あなた決めたルールでは、どちらを大きいとしますか? 数字なら5の方が大きいでしょう、では、数字ではなくコードだとしたら? あなたの作成するプログラムでは、 コードの2は、ドラゴン、  コードの5は、スライムかもしれません。 モンスターの名前順、レベル順、攻撃力順、 あるいは、モンスターの名前の逆順、レベルの逆順、攻撃力の逆順 モンスターの名前順なら、「あ」が一番小さく、「ん」が一番大きいとして 名前の逆順なら、「ん」が一番小さく、「あ」が一番大きい値です。 レベル順なら、レベル1が一番小さく、レベル99が一番大きい値です レベル逆順は、レベル99が一番小さな値で、レベル1が一番大きな値です そもそも、 数字の2と5を比較して5の方が大きいから負の数を返すなら、この関数の存在意義が無いですよね

salyuun
質問者

お礼

たしかに、例示されているのが数値ではなく文字列だったら疑問に思わなかったかもしれません。ありがとうございました。

  • Tacosan
  • ベストアンサー率23% (3656/15482)
回答No.2

慣例として「大きい」「小さい」っていっちゃうんだけど, 「後ろに来る」「前に来る」と書いてあるものだと思ってください.

salyuun
質問者

お礼

たしかに、ソートして上にしたいものを、みたいにそのまま捉えると理解できます。ありがとうございました。

  • nak777r
  • ベストアンサー率36% (49/136)
回答No.1

何をもって大きいとするかを指定できる仕様なのです 例えば、トランプの場合、1が13よりも大きい数字になったりしますよね 文字列の"2" と文字列の"10" では、先頭の文字が "1" と "2" なので "2" の方が 大きくなります。 でも実際は、"10" なのでこちらを大きくしたいと考える場合が ありますよね、何をもって大きいとするかを決めるのは、設計者の仕様のはんちゅうです。

salyuun
質問者

お礼

評価としての大小、ということですね。理解できました。ありがとうございます。

関連するQ&A

  • PHPのusort関数について

    PHPにおけるusort関数およびuasort uksort関数の使い方がわかりません。 $array = array("b" => "bbbb","c" => "cc","d" => "ddddddddddd","e" => "eee","a" => "a","f" => "ffffffff","g" => "gg","h" => "hh"); 上記のような配列があった場合 uasort($array, function($a,$b){ if (strlen($a) == strlen($b)) { return 0; } if(strlen($a) > strlen($b)){ return -1; }else if(strlen($a) < strlen($b)){ return 1; } } ); print_r($array); 上記のようなコードの場合 ( [d] => ddddddddddd [f] => ffffffff [b] => bbbb [e] => eee [h] => hh [g] => gg [c] => cc [a] => a ) という結果がかえてきます。 ただ、実際このコードでなにがおきてるかわかりません。 まず、uasort関数の第二引数に渡す関数の引数 $a,$bはいったいどんな順番で第一引数の配列からわたされているのでしょうか? そして、$a と$ bの値が同じ場合に0を返した場合なにがおきてるのでしょうか? 同じく return 1;を返すときと return -1;を返すときと いったいどのような処理がおこなわれていてどういうなぜ 上記のような配列を返すことになるのでしょうか? そもそも PHPマニュアルから参照しますが 比較関数は、最初の引数と二番目の引数の比較結果を返します。最初の引数のほうが二番目の引数より大きい場合は正の数を、二番目の引数と等しい場合はゼロを、そして二番目の引数より小さい場合は負の数を返す必要があります。 上記説明も、どうにも理解できません。 どうも全体的にusort関数系の使い方がわかりません。 識者の方よろしくご教授いただけますようお願いします。

    • ベストアンサー
    • PHP
  • php多次元配列のソート(usort)について

    http://www.php.net/manual/ja/function.usort.php にusortの例として下記がありますが、それについて質問です。 -------------例文------------- <?php function cmp($a, $b) { return strcmp($a["fruit"], $b["fruit"]); } $fruits[0]["fruit"] = "lemons"; $fruits[1]["fruit"] = "apples"; $fruits[2]["fruit"] = "grapes"; usort($fruits, "cmp"); while (list($key, $value) = each($fruits)) { echo "\$fruits[$key]: " . $value["fruit"] . "\n"; } ?> -------------結果------------- $fruits[0]: apples $fruits[1]: grapes $fruits[2]: lemons 上の例は、usortで$fruitsという配列をソートしています。 そのとき、cmpという関数を条件にしている、というのは分かりますが、 なぜcmpを条件にすることでアルファベットの昇順になるのでしょうか? strcmp($a["fruit"], $b["fruit"]);にたとえばlemonsとかapplesが入って strcmpによって比較がされて、結果として1や-1が返されて その結果、たとえばusort($fruits, "-1")や、usort($fruits, "1") となったとします。それがなぜ結果として昇順になるのでしょうか?

    • ベストアンサー
    • PHP
  • 【PHP】usort()関数内の引数について

    【PHP】usort()関数内に出てくる関数の引数の意味を教えてください。 usort(ユーザー定義関数) 以下のような配列があります。ここで'score'を小さな順番(昇順)で並べ替えるためにusort()関数を使いたいと思います。 $data= [ ['name' => 'yamada', 'score'=> 80], ['name' => 'suzuki', 'score'=> 60], ['name' => 'tanaka', 'score'=> 70], ['name' => 'okada', 'score'=> 60], ]; usort( $data, function($a, $b){ if ($a['score']=== $b['score']){ return 0; } return $a['score'] > $b['score'] ? 1: -1; } ); echo "<pre>"; print_r($data); echo "</pre>"; ----------------------------------------------------------------- サンプルでは上記のように$a,$bが使用されています。 スコアの数値を比較して、あるスコアの値と別のスコアの値が同じであれば「0」を返す。$aの値が$bより大きければ「1」を返す、そうでなければ「-1」を返す。 返ってきた値、「-1」,「 0」,「 1」と小さな順に並べる… こういうことかと思います。添付画像のように表示された値も合っています。 が、functionの引数($a, $b)の意味がよくわかりません。 foreachなどでループさせ値を一つづつ比較するというよう作業を行うのであればまだ理解できるかもしれませんが、ただ単に引数に function($a, $b)…としただけでscoreの値が$a、$bにどうやって代入されていくのでしょうか?? $a, $bと記述しただけで全てのscoreの値をなぜ比較してくれるのかわかりません。 また、現在$dataの中には4つしか配列がありません。-1,0,1だけで順番をつけられるでしょうが、これが50, 100個と配列データが増えた場合でもこのやり方でできるのでしょうか? 初学者です。分かる方いらっしゃいましたら教えて下さい。よろしくお願いいたします。

    • ベストアンサー
    • PHP
  • usortの使い方

    お世話になります。 下記の様なデータが在ります。 ------------------------- | namae | age | hantei | ------------------------- | かんざき | 32 | 1 | ------------------------- | みやざき | 39 | 2 | ------------------------- | あんざき | 26 | 1 | ------------------------- | まえざき | 32 | 1 | ------------------------- | しもざき | 29 | 2 | ------------------------- | あんざき | 26 | 1 | ------------------------- このデータを[namae]で50音順に並び替えることは出来るのですが、[hanntei]でソートさせた後に[namae]でソートしたいです。 上記データが$nameに格納されています。 usortの使い方を教えて下さい。 //優先順位比較 function namecmp($a, $b) { return $a["namae"] > $b["namae"]; } //配列の並べ替え usort($name, "namecmp"); 宜しくお願いします

    • ベストアンサー
    • PHP
  • 連想二次元配列のUNIXTIMEでのソート

    ID(主キー)、unixtime、nameをフィールド名とするとするSQLのデータベースを取得してUNIXTIMEを比較してソートするようなPHPを作りました。   $contents= array(); $temp = mysql_query($query, $link ); while( $contents = mysql_fetch_array($temp, MYSQL_ASSOC)){ } //比較してソート function cmp($a, $b) { print_r($a); if ($a["unixtime"] == $b["unixtime"]) { return 0; } return ((int)$a["unixtime"] < (int)$b["unixtime"]) ? 1 : -1; } usort($contents, "cmp"); しかしこれを実行したところ、 Warning: usort() expects parameter 1 to be array, boolean given in C:\xampp\htdocs\php\outstr.php on line 49 となってしまいます。 usortのエラーのようですが、なぜこうなってしまうのでしょうか。 正常にソートできるような方法を教えてください。

    • ベストアンサー
    • PHP
  • Array.sortメソッドのデフォルト比較関数

    JavaScriptのArray.sortメソッドは、 引数を指定しなければデフォルトの比較関数でソートされますが、 この比較関数を取り出して利用できないでしょうか。 要件は、プロパティ[name]と[value]を持ったオブジェクトの配列のソートです。 nameプロパティは半角英数字の文字列で、これをキーにソートしたいと考えています。 ソートの基準は、Array.sortのデフォルトと同じです。 つまり、こんなコードを想定しています。 var ary = [o1, o2, o3]; // o1~o3はそれぞれ上記のオブジェクト ary.sort(function(a, b){ return compare(a.name, b.name); }); このコードにおけるcompare関数を、Array.sortのデフォルト比較関数にしたいのですが、 これは自前で作成するしかないのでしょうか。 数値だけでなく文字列全般の比較になるので、結構実装が面倒そうなのですが、 自作する場合に何か使えそうな標準関数等、無いでしょうか。 今のところ思いついているのは、下記みたいなものです。 var compare = function(a, b) {  var temp = [a, b];  temp = temp.sort();  return temp[0] === a ? -1 : 1; } 比較関数内で更にArray.sortを呼んで2項目をソートし、 順番が入れ替わったかどうかを判定するだけです。 何だか冗長で気持ち悪いコードですので、代案を探しています。

  • イプシロン値を使った比較関数

    先日、↓でイプシロン値の記述方法を質問し、お陰様で一つ賢くなりました・・・ https://okwave.jp/qa/q9625188.html 今回、このイプシロン値を使用して2つの浮動小数点数の比較関数を作ってみました。 ところが、意図した結果になりません(数値により正しく判断できない場合がある) //倍精度浮動小数点数比較関数 //相対誤差内であれば、両者は等しいとする //戻り値 a=bのとき:0 a≠bのとき:0以外 #include <math.h> int CompareDoubleValue(const double a, const double b) { //引数の差の絶対値とイプシロン値を使用した相対誤差を比較する //1と引数の大きい方の数値を比較して、より大きい数値をイプシロン値 //と乗算して相対誤差とする if (fabs(a-b) <= (DBL_EPSILON*fmax(double(1), fmax(a, b)))) return(0); else return(-1) ; } ※fabs():倍精度浮動小数点数の絶対値を求める標準関数 ※fmax():2つの引数(倍精度浮動小数点数)の大きいほうの値を返す標準関数 何が悪いのかわからず困っております。 お教え頂けると幸いです。 よろしくお願いします。

  • perlで比較関数を使ったソートの仕方

    今、季節をソートするようなプログラムを考えています。 my @array = ('spring','fall','winter','summer'); my @sort = sort number(@array); sub number { if ($a < $b) { return -1; } elsif ($a == $b) { return 0; } elsif ($a > $b) { return 1; } } 実行結果:spring ,summer ,fall ,winter 比較関数を使用して、「春・夏・秋・冬」とソートできるようにしたいです。上のプログラムはまだ途中なんですが、この場合比較関数はどのように実装すればうまくソートできるんでしょうか?分かる方、よろしくお願いいたします。

    • ベストアンサー
    • Perl
  • PHPのstrcmp関数について

    PHPのstrcmp関数の動きがよくわかりません。 strcmp (PHP 4, PHP 5) strcmp — バイナリセーフな文字列比較 説明 int strcmp ( string $str1 , string $str2 ) この比較は大文字小文字を区別することに注意してください。 パラメータ str1 最初の文字列。 str2 次の文字列。 返り値 str1 が str2 よりも小さければ < 0 を、str1が str2よりも大きければ > 0 を、 等しければ 0 を返します。 ・・・・・・・・・とマニュアルには上記のようにあります。 聞きたい事!▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼ 1 このstr1がstr2より大きいとはどういうことでしょうか? 2 実際に動きを確認するためにstrcmp関数を他のPHPのビルトイン関数で実現できないのでしょうか? 私の想像では、この関数にあたえる二つの引数を10進数に変換して、値の大きさを比較するという方法なのですが・・。 たとえば <?php $str01 = "a"; $str02 = "b"; print strcmp($str01,$str02); print "<br />"; //上記の値は-1がでるためこの場合 $aのほうが$bより小さいことになる。 //$aの値の文字aが小さいとは?どういうことか //私の、ぱっと思いついた方法は、以下のような意味? $str01 = bin2hex($str01); print $str01 ; //16進数でaという値を表すと61がでる print "<br />"; $str01 = hexdec($str01); print $str01; //10進数でaという値を表すと97がでる print "<br />"; //上記を同じく$bに行うと $str02 = bin2hex($str02); print $str02 ; //16進数でaという値を表すと62がでる print "<br />"; $str02 = hexdec($str02); print $str02; //10進数でaという値を表すと98がでる print "<br />"; print "<hr />"; /* 結果、$aは$bより 【小さい】という事なのでstrcmpは-1を返したと・・・。 こういう事をかんがえてみました。 そしてこれは、普通に考えれば a => bという順序なので アルファベット順になります。 しかしこのやり方だと */ $str03 = "aaaaaaa"; $str04 = "bb"; //と上記のような文字列があった場合同じく同じ手順で値をだすと $str03 = bin2hex($str03); print $str03 ; //16進数でaという値を表すと61616161616161がでる print "<br />"; $str03 = hexdec($str03); print $str03; //10進数でaという値を表すと27410143614427489がでる print "<br />"; //上記を同じく$bに行うと $str04 = bin2hex($str04); print $str04 ; //16進数でaという値を表すと6262がでる print "<br />"; $str04 = hexdec($str04); print $str04; //10進数でaという値を表すと25186がでる print "<br />"; /*ただ上記の方法だと、$str03と$str04を比較すると$str04の【bb】という値の方が 小さくなり順序的には bb => aaaaaaとなりアルファベット順にするとこができない。 三つ目の質問 3 アルファベット順にソートしたいとき標準のsort関数を使わずに他のPHPの標準関数の組み合わせでアルファベット順に並び替える 関数はつくれないのか? どなたか、ご意見お聞かせください。 よろしくお願いします。

    • ベストアンサー
    • PHP
  • bsearch関数の呼び出しで

    C言語の深いところまで理解しようとしてます。今まで使わないだろうと思っていた関数へのポインタ なのですが、 2分探索のところで bsearch関数というのが出てきました。 この関数は第5引数に比較関数を引数にするのですが p = bsearch(&ky, x, nx, sizeof(int), (int (*)(const void *,const void *))int_cmp ); という形でサンプルソースには載っています。 この (int (*)(const void *,const void *))int_cmp の部分なのですが、まず戻り値をキャストするなら int (*)ではなく(int *)ではないでしょうか。 それとint_cmpは比較関数なのですが、引数が左側に来る、というところが納得できません。 ちなみにソースファイルをcppのままだとコンパイルできませんでした.cに拡張子を直したらコンパイルできました。 説明が足りないところがあったら指摘してください。お願いします。

専門家に質問してみよう