配列のソートと無名関数

マンガで分かる JavaScriptプログラミング講座

マンガで分かる JavaScriptプログラミング講座 第2版



第2部 脱初心者プログラミング
第14話:配列のソートと無名関数

目次



マンガ


















マンガ台詞

【1Page】
麗:うーん 大変だわ
先生:どうしたんだ?
麗:生徒会で 各部活の予算を 決めているんですが 予算順に整理する のが大変で
遊:ふふふ 甘いわね麗!
    あんたはまだ プログラム脳に なりきれていないわ!
    こんな時こそ プログラムよ!
麗:むっ あなたは どうすれば 整理できるのか 分かるの?
遊:簡単よ
    先生にプログラムを 書かせればいいのよ!
先生:おいっ
【2Page】
先生:とはいえ プログラムで楽をしよう という考え方は正しい
    そういえば まだ『ソート』は 詳しく説明して いなかったな
遊:『ソート』って 何なの?
先生:配列を並び替える処理だ
    配列の『ソート』関数を使えば 値を並べ替えてくれる
        var yosan = [20000, 10000, 12000, 15000];    // 配列作成

        yosan.sort();    // 小さい順にソート
        alert(yosan);    // 配列を表示

        yosan.reverse();    // 向きを逆に
        alert(yosan);    // 配列を表示
    (小さい順)『10000,12000,15000,20000』と表示
    (向きを逆にして大きい順)『20000,15000,12000,10000』と表示
麗:書いていただいたのは ありがたいのですが
    これではどの数字が どの部活か分かりません
【3Page】
先生:そういった場合は 関数を引数にして 『ソート』する
    実例を 示そう
    詳しい解説は 次のページ から行うぞ
        // 配列
        var yosanArray = [
             {namae:"野球部", yosan:20000}
            ,{namae:"サッカー部", yosan:10000}
            ,{namae:"卓球部", yosan:12000}
            ,{namae:"写真部", yosan:15000}
        ];

        // ソート
        yosanArray.sort(
            function (a, b) {
                var aYosan = a["yosan"];
                var bYosan = b["yosan"];
                if (aYosan < bYosan) return -1;
                if (aYosan > bYosan) return 1;
                return 0;
            }
        );

        // 一覧表示
        for (var i = 0; i < yosanArray.length; i ++) {
            document.write(
                  i + " : "
                + yosanArray[i]["namae"]
                + ","
                + yosanArray[i]["yosan"] + "<br>"
            );
        }
    『0 : サッカー部,10000,
    1 : 卓球部,12000,
    2 : 写真部,15000,
    3 : 野球部,20000,』と表示
麗:なるほど これなら部活名も分かり 便利ですね
【4Page】
先生:それではまず ソートの予備知識 を説明する
    『sort』メソッドの引数は 『function (a, b) {〜}』 になっている
    このような 『名前のない関数』は 『無名関数』と呼ぶ
        配列.sort(function (a, b) {〜});
        無名関数
先生:『sort』の引数の『無名関数』は 『a』『b』2つの引数を取る
    この引数を比較して 戻り値を戻せば 配列の順序が変わる
        戻り値    並べ替え
        -1    小さいと見なして前に移動
        0    並べ替えなし
        1    大きいと見なして後ろに移動
先生:それでは実際の プログラムの 解説だ
    今回 ソート用のデータとして
    『yosanArray』という 配列を用意した
        var yosanArray = [    // 『yosanArray』配列
            // 配列の各要素は連想配列になっている
             {namae:"野球部", yosan:20000}    // 0番目の要素
            ,{namae:"サッカー部", yosan:10000}    // 1番目の要素
            ,{namae:"卓球部", yosan:12000}    // 2番目の要素
            ,{namae:"写真部", yosan:15000}    // 3番目の要素
        ];
【5Page】
先生:配列のソートを行うと
    『function (a, b) {〜}』
    の引数『a』『b』に
    配列の要素である連想配列が
    代入されて 関数が実行される
        {namae:"野球部", yosan:20000}
            {namae:"サッカー部", yosan:10000}
        yosanArray.sort(
            function (a, b) {
                引数『a』『b』の比較
先生:関数内の処理では
    引数『a』『b』を
    連想配列として扱い
    値を取り出している
    あとは取り出した 2つの予算の値を 比較すればよい
        function (a, b) {
            var aYosan = a["yosan"];    // 値は『20000』
            var bYosan = b["yosan"];    // 値は『15000』
            if (aYosan < bYosan) return -1;    // 前に移動
            if (aYosan > bYosan) return 1;    // 後ろに移動
            return 0;    // 並べ替えなし
        }
先生:最後は出力部分だ
    連想配列の値を 『namae』『yosan』キーで 取り出している
        for (var i = 0; i < yosanArray.length; i ++) {
            document.write(
                  i + " : "
                + yosanArray[i]["namae"]
                + ","
                + yosanArray[i]["yosan"] + "<br>"
            );
        }
【6Page】
麗:比較を自由にできるなら いろいろと応用 できそうですね
先生&麗&守:(話している)
遊:うぐぐ 話についていけないわ 何かしゃべらないと
    先生!
    『sort』の『引数』は 『無名関数』ではなくて 名前のある関数でも いいのですか?
先生:遊くん!
遊:ひいっ ごめんなさい
    適当に言いました
【7Page】
先生:素晴らしい
    そうなんだ!
遊:へっ?
先生:ソート部分は こういう風に 書くこともできる
        yosanArray.sort(bukatuSort);

        function bukatuSort (a, b) {
            var aYosan = a["yosan"];
            var bYosan = b["yosan"];
            if (aYosan < bYosan) return -1;
            if (aYosan > bYosan) return 1;
            return 0;
        }
先生:こう書いてもいいぞ
        var bukatuSort = function (a, b) {
            var aYosan = a["yosan"];
            var bYosan = b["yosan"];
            if (aYosan < bYosan) return -1;
            if (aYosan > bYosan) return 1;
            return 0;
        };

        yosanArray.sort(bukatuSort);
【8Page】
3人:ぽかーん。
先生:はっ また 先走ってしまったか
遊&麗:ううう 私たち 先生に虐められて いるのかしら?
先生:あー すまん
    難しくならないように 気をつけるよ



説明

この章では、配列の『ソート』と『無名関数』について学びます。

配列は、その並び順を昇順(小さい順)に並べ替えるための『sort』メソッドを持っています。また、配列を逆順に並べ替える『reverse』メソッドも持っています。そのため、昇順に並べ替えて、逆順にすることで、降順(大きい順)に並べ替えることも可能です。

この、配列を『ソート』する『sort』メソッドですが、引数を取り、特殊なルールで配列を並べ替えることもできます。『sort』メソッドは、引数として関数(『function』型オブジェクト)を取ります。そして、この関数内で、引数として与えられた2つの要素が『小さいか大きいか』を判定して、戻り値として戻すことで、並べ替えの順番を決めます。

この『sort』メソッドの引数として、多くの場合『無名関数』と呼ばれる特殊な関数が使われます。『無名関数』は、『型、オブジェクト、クラス』の章で、軽く触れました。この『無名関数』は、名前を持たない関数です。

『無名関数』は多くの場合、『sort』メソッドなどの使い捨ての引数として使われます。また、変数に処理を格納する目的で利用されます。

それでは以下、『ソート』と『無名関数』について解説していきます。



配列の『ソート』

配列オブジェクトには、いくつかのメソッドがあります。その中の1つである『sort』メソッドを使えば、配列を数字の小さい順に並べ替えることができます。

var yosan = [20000, 10000, 12000, 15000];    // 配列作成
yosan.sort();    // 小さい順にソート
alert(yosan);    // 配列を表示
 【結果】
 10000,12000,15000,20000

また、『reverse』メソッドを使うことで、配列を逆の順番に並べ替えることができます。

いったん小さい順にソートしておいて、『reverse』で逆順にすることで、大きい順に並べ替えることもできます。

yosan.reverse();    // 向きを逆に
alert(yosan);    // 配列を表示
 【結果】
 20000,15000,12000,10000

それでは以下、ソートについて、さらに深く学んでいくことにしましょう。



引数を取る『ソート』

さて、この『sort』メソッドですが、引数として関数(『function』型オブジェクト)を取ることができます。

var yosan = [20000, 10000, 12000, 15000];    // 配列作成
yosan.sort(function (a, b) {/* 要素の比較 */});    // 『function』型の変数を引数に設定

引数に指定した関数『function (a, b) {〜}』は、『sort』メソッドが配列を並べ替える際に呼ばれます。

具体的にどのように呼ばれるのかを、手順として示します。

  1. 『sort』メソッドは、並べ替えのために比較したい2つの要素を選ぶ。
  2. 『sort』メソッドは、選んだ2つの要素を引数にして、関数を呼び出す。
    1. 呼ばれた関数は、第1引数に1つ目の要素を、第2引数に2つ目の要素を受け取って処理を開始する。
    2. 呼ばれた関数は、2つの要素を比較して、どちらが前か後かを、戻り値として戻す。
  3. 『sort』メソッドは、呼んだ関数の戻り値を元に、選んだ2つの要素を並べ替える。
  4. 『sort』メソッドは、次に比較したい要素があるか確認する。
    1. ある場合は最初に戻る。
    2. ない場合は処理を終了する。

引数として指定した関数は、呼び出される際に、2つの引数を取ります。この引き数は、『sort』メソッドが配列から選んだ2つの要素です。

上記のプログラムの例では、引数『a』『b』として、比較用の2つ要素を受け取ります。関数では、この引数『a』『b』を比較します。そして、『aはbの前か』『aはbの後ろか』を決めて、戻り値を戻します。この戻り値に従って、『sort』メソッドは、配列を並び替えていきます。

関数の戻り値として、『-1』を戻せば『a』を『b』より前に移動します。『1』を戻した場合は、『a』を『b』の後ろに移動します。『0』を戻した場合は、並び順を変更しません。この対応表を、以下に示しておきます。

戻り値並べ替え意味
-1『a』を『b』より前に移動『a』の方が小さいと判断
0並べ替えなし『a』と『b』は同じ
1『a』を『b』の後ろに移動『a』の方が大きいと判断

引数を取らない『sort』メソッドは、小さい順に配列を並び替えます。関数を利用した『sort』メソッドも、この小さい順の並べ替えを元に考えると理解しやすいです。なぜならば、戻り値として『-1』(-1,0,1の中でで最も小さい数字)を指定した場合は、「『a』が『b』より小さいと判断した」ということになるからです。



『無名関数』

『sort』の引数として、『function (a, b) {〜})』のような関数を指定しました。この関数は、『function』のあとに関数名がありません。このように、名前のついていない関数のことを、『無名関数』と呼びます。

JavaScriptでは、この『無名関数』を多用します。この先、様々な関数の引数として、『無名関数』を利用することになります。また、クラスなどを自分で作る際にも『無名関数』を使うことになります。そのためここで、『無名関数』の取り扱い方を覚えてください。

それでは以下、2つの利用シーンでの『無名関数』を解説します。

使い捨ての関数としての『無名関数』

『無名関数』のメリットは、使い捨ての関数を簡単に作れることです。この使い捨ての関数は、メソッドの引数として、よく利用されます。

以下、『無名関数』を利用したプログラムの例です。

// 『sort』の引数として、使い捨ての関数を作成して利用する
var no = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];    // 配列作成
no.sort(function (a, b) {
    // 偶数を前に、奇数を後ろにソートする
    if (a % 2 == 0 && b % 2 != 0) return -1;
    if (a % 2 != 0 && b % 2 == 0) return 1;
    return 0;
});
alert(no);    // 『2, 4, 6, 8, 10, 1, 3, 5, 7, 9』と表示

『function (a, b) {〜}』という『無名関数』を、『sort』メソッドの引数としています。

変数に格納する『無名関数』

『無名関数』のもう1つの使い方は、変数に格納するというものです。これは、クラスを作る際などに多く利用されます。

以下、『型、オブジェクト、クラス』の章で出てきたプログラムを示します。

// 生徒クラスを作成
var Seito = function(namae, tensuu) {
    this.namae  = namae || "???";
    this.tensuu = tensuu || 0;
    this.show = function() {
        window.alert("名前 : " + this.namae + " / 点数 : " + this.tensuu);
    };
};

変数『this.show』に、『function() {〜}』という『無名関数』を入れています。このように、一定の処理を変数として扱いたい時に『無名関数』は威力を発揮します。

また、『無名関数』は、クラスだけではなく、変数や関数を共通のオブジェクトの配下にまとめたい時にも利用されます。以下、その例です。

var myFunctions = new Array();    // オブジェクトを作成

myFunctions.alertTitle = function () {alert(document.title)};
        // 『alertTitle』というプロパティに、関数を代入

myFunctions.alertTitle();
        // 『alertTitle』メソッドを実行して、Webページのタイトルを表示する

変数『myFunctions.alertTitle』に、『無名関数』を代入しています。



マンガ中のプログラムの解説

それでは以下、マンガ中で出てきたプログラムの解説を行います。

// 変数の初期化
var yosanArray = [
     {namae:"野球部", yosan:20000}
    ,{namae:"サッカー部", yosan:10000}
    ,{namae:"卓球部", yosan:12000}
    ,{namae:"写真部", yosan:15000}
];

// ソート
yosanArray.sort(
    function (a, b) {
        var aYosan = a["yosan"];
        var bYosan = b["yosan"];
        if (aYosan < bYosan) return -1;
        if (aYosan > bYosan) return 1;
        return 0;
    }
);

// 一覧表示
for (var i = 0; i < yosanArray.length; i ++) {
    document.write(
          i + " : "
        + yosanArray[i]["namae"]
        + ","
        + yosanArray[i]["yosan"] + "<br>"
    );
}

このプログラムでは、まず最初に、配列を作成しています。この配列の中には、各要素として連想配列が格納されています。この連想配列の要素は、『yosanArray[0]["namae"]』のようにして参照することができます(この場合の値は『野球部』)。

次に、この『yosanArray』オブジェクトの『sort』メソッドの引数に『無名関数』を入れて、ソートを行います。

この『無名関数』は、呼び出されるたびに、引数『a』『b』という、比較用の値を受け取ってから処理を行います。この引数『a』『b』には、配列の要素がそれぞれ代入されています。『yosanArray』配列の要素は、『{namae:"野球部", yosan:20000}』といった連想配列なので、これらの連想配列が順次代入されて実行されます。

このソート部分では、引数の連想配列から、『aYosan = a["yosan"]』『bYosan = b["yosan"]』のようにして予算の値を取り出しています。なぜならば、『a』『b』の引数は、『yosanArray』の要素、つまり連想配列(『{namae:"野球部", yosan:20000}』のような値)だからです。

そして、『aYosan』『bYosan』の数値を比較してソートを実行しています。引数『a』の予算が小さい場合は戻り値を『-1』に、大きい場合は戻り値を『1』にしています。同じ場合は『0』です。この結果、予算が小さい要素ほど、前に並びます。

最後は一覧表示です。この部分では、『yosanArray』配列の各要素(連想配列)を文字列にして出力しています。『yosanArray[i]["namae"]』の部分では名前を、『yosanArray[i]["yosan"]』の部分では予算を取り出して、文字列として連結しています。



『ソート』の引数に、名前付きの関数を使う

これまで、『sort』メソッドの引数に、名前のない『無名関数』を指定してきました。この『sort』メソッドの引数には、名前のついた関数を指定することもできます。何度も使うソート方法は、名前付きの関数にして、あとで呼び出せるようにした方が便利です。

以下、名前付きの関数を利用して、ソートを行う例を示します。

// ソートの引数に使う関数を初期化
function guusuuSort (a, b) {
    // 偶数を前に、奇数を後ろにソートする
    if (a % 2 == 0 && b % 2 != 0) return -1;
    if (a % 2 != 0 && b % 2 == 0) return 1;
    return 0;
}

// 配列をソート1
var no1 = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];    // 配列作成
no1.sort(guusuuSort);
alert(no1);    // 『2, 4, 6, 8, 10, 1, 3, 5, 7, 9』と表示

// 配列をソート2
var no2 = [11, 12, 13, 14, 15, 16, 17, 18, 19, 20];    // 配列作成
no2.sort(guusuuSort);
alert(no2);    // 『12, 14, 16, 18, 20, 11, 13, 15, 17, 19』と表示

上記のプログラムでは、『ソート』の引数に使う関数を、独立した名前付きの関数として作成しています。そして、『no1.sort(guusuuSort)』『no2.sort(guusuuSort)』のように、引数として利用しています。

何度も行う『ソート』方法がある場合は、このように関数にして再利用すると便利です。



『ソート』の多様な書き方

短く書く

マンガ中では、分かりやすくするために、ソート部分をわざと長めに書きました。ある程度プログラムに慣れた人は、もう少し短く書くことができるでしょう。

以下、短く書いた例を挙げておきます。

yosanArray.sort(
    function (a, b) {return (a["yosan"] < b["yosan"]) ? -1 : 1;}
);

この式では、『a["yosan"]』が小さければ『-1』(前へ移動)、それ以外の場合は『1』(後ろへ移動)という数値を、戻り値として設定しています。

連想配列ではなく、普通の配列で書く

ソート用の配列の各要素を、『連想配列』ではなく、普通の配列で書くこともできます。

以下、例を挙げます。

<html>
    <head>
        <script type="text/javascript">
        <!--
        var yosanArray = [
             ["野球部",     20000]
            ,["サッカー部", 10000]
            ,["卓球部",     12000]
            ,["写真部",     15000]
        ];

        // ソート
        // 引数『a』や『b』には『["野球部", 20000]』のような配列が設定される
        // 予算の数値は、配列の2番目の要素なので『a[1]』と書くことで参照できる
        yosanArray.sort(
            function (a, b) {return (a[1] < b[1]) ? -1 : 1;}
        );

        // 一覧表示
        for (var i = 0; i < yosanArray.length; i ++) {
            document.write(
                  i + " : "
                + yosanArray[i][0]
                + ","
                + yosanArray[i][1] + "<br>"
            );
        }
        // -->
        </script>
    </head>
    <body>
    </body>
</html>

『a[1]』『b[1]』と、連想配列ではなく、配列として引数を利用しています。

この際、『a』『b』は、『yosanArray』の要素(この場合は配列)を表します。また、添え字の『1』は、配列の2番目の値を示します。この場合は、『予算にあたる数字』を指し示すことになります。



サンプルの入手

以下は、今回出てきたサンプルです。

ZIPでまとめてダウンロード (右クリックから保存してください)

sample1.html』(単純なソート)を表示

sample2.html』(連想配列を利用したソート)を表示

sample2b.html』(書き換え1)を表示

sample2c.html』(書き換え2)を表示

sample2d.html』(短い版)を表示

sample3.html』(通常配列版)を表示

sample4.html』(偶数を前に、奇数を後ろにソート)を表示

sample5.html』(オブジェクトの変数に無名関数を代入)を表示

sample6.html』( ソートの引数に使う関数を名前付きで作成)を表示

プログラムの中身を見たい場合は、それぞれのHTMLファイルをブラウザで開いたあと、右クリックをして『ソースの表示』を選択してください。

メモ帳で、ファイルの中身を見ることができます。

≫ 「マンガで分かる JavaScriptプログラミング講座」トップに戻る


『柳井政和』 の初心者向け講座

『柳井政和』 のサイト

マンガで分かる Java入門講座
Javaのオブジェクト指向を解説するサイトです。
Webページ100ページ以上、マンガ800ページ以上で
解説を行っています。


PuzzleAndGame.com
JavaScriptで作ったゲームが中心のサイト。
タワーディフェンス、リバーシ、パズルゲームなどを公開。
Webブラウザ、PCアプリ、Androidアプリとして動作。


クロクロ・ツールズ
全てJavaScriptで作られた、ブラウザから利用できる各種アプリケーションです。
HTML5に対応しているモダンブラウザから使えます。
ブックマークに入れるなどして、ご利用ください。


『柳井政和』 執筆の本

「裏切りのプログラム ハッカー探偵 鹿敷堂桂馬」
文藝春秋より発売(2016年8月27日発売、予約注文可能です)。
2016年の松本清張賞で、最終候補に残った小説です。
プログラマー鹿敷堂桂馬が、女性社長の安藤裕美とともに、
IT業界で起きた事件の解決に挑みます。
プログラマーが探偵役のエンタメ・ミステリーです。


「JavaScript 仕事の現場でサッと使える! デザイン教科書」
プログラミング初心者向けに、様々な利用例を元に、プログラムとJavaScriptを解説する本。
プログラム自体が初めての方にも、なるべく分かりやすいように書いています。
技術評論社より発売。


「プログラマのためのコードパズル〜JavaScriptで挑むコードゴルフとアルゴリズム」
コードゴルフやアルゴリズム問題、その解説、関連知識の紹介を行った本です。
プログラマーなら、楽しめる内容になっています。
技術評論社より発売。


「マンガでわかるJavaScript」
本講座が書籍になりました。 本用に、より分かりやすく、読みやすく、再構成して書き直しました。
よければ、手にとっていただけると嬉しいです。
秀和システムより発売。


「マンガでわかるJavaプログラミング」
プロ部の面々が、今度はjavaのプログラミングに挑戦。
javaを1から学ぶ人向けの書籍です。
秀和システムより発売。 詳細情報


古い本
HTML5&JavaScript本格ゲームプログラミング 〜ライブラリ自作からはじめるブラウザゲーム開発
マンガでわかるAndroidプログラミング 第2版
Google Androidアプリ開発ガイド 第3版
プロならば知っておくべきWebコーディング&デザインの定石100

『柳井政和』 開発のWebアプリやソフトなど

PuzzleAndGame.com
全自動4コマ
全自動百科事典(オートペディア)
全自動似顔絵
新刊・新作カレンダー
EX リバーシ
全自動迷路
めもりーくりーなー
ラジオ・ブラウザ
PCソフト
マンガで分かる JavaScriptプログラミング講座
スクリーンセーバー「なう」
開発元:クロノス・クラウン




Cronus Crown(クロノス・クラウン)のトップページに戻る
(c)2002-2017 Cronus Crown (c)1997-2017 Masakazu Yanai
このWebPageに関するご意見・お問い合わせは
サイト情報 - 弊社への連絡 -
までお願いします。