ちょっと躓いたので備忘録も兼ねて残しておきます。ちょっとだけツイートした二重配列のソートについてです。
二重配列と配列に対するsortメソッドについては既に知っているよ、という方は本題まで読み飛ばしてください。以下、本題までおさらいを兼ねて文字にしてます。
二重配列とは
そもそも二重配列(二次元配列ともいう)とは、下記のような配列を指します。
var arr = [ [0,1], [1,3], [2,4] ];
要するに配列の要素に配列が入っている状態です。取り出すときはこんなふうにします。
alert (arr[2][1]); //結果は4
sortメソッド
配列を並び替えるメソッド(関数)で、もともとの本家JavaScriptが持っているものです。詳細はMDN等を参照ください。
一応少しだけ触れておくと、例えばこんなふうに使います。
//数値を比較する場合 var arr = [ 4, 1, 2, 6, 8, 11, 9 ]; arr.sort (function (a,b){return a-b}); //結果は1,2,4,6,8,9,11 //※文字列を比較してソートする場合はまた別の関数を用意する必要がある
sortメソッドに、2つの引数を持つ関数を渡すのが一般的です。
関数function (a,b)
の結果が正となるか、負となるか、0なのか、で配列の並び順をコントロールします。なのでここに記述する関数がsortメソッドの肝です。
論理演算子||
後で出てくる論理演算子OR(||
)について、先にちょっと説明しておきます。これは論理演算子の一つで、俗に「論理OR」などと呼ばれます。if文などでお馴染みのやつですね。
この論理演算子は、AもしくはB、というときの「もしくは」と近い結果を返すことは、if文を使ったことがあればなんとなくわかると思います。
var A = 10, B = 5; alert(A > B || A < B);//結果はtrue
この例では「AがBより大きい場合」もしくは「AがBより小さい場合」と、A=Bでない限りture
が返ることになります(AとBを同値にすると、結果はfalse
です)。
ではこういうケースではなんと表現すればいいでしょうか。
var A = 10, B = 5, C = 2; alert (A-B || B-C);
この場合の論理演算子ORの式の評価のしかたを言葉で説明しようとすると、先ほどのように「もしくは」とはちょっと言いにくいですね。
この論理演算子ORは、やっぱり「演算子」なのです。四則演算の+
や-
のように頭から順に処理を行うと考えてみてください。
まずA-B
の式の評価を行います。仮にA>B
だった場合、式の結果は正の値を取ります。A=B
であれば値は0ですし、A<B
であれば負になります。その時の論理ORは何を返すでしょうか。こんな実験をしてみるとわかりやすいかもしれません。
alert (-1 || 1); //-1 alert (0 || 1); //1 alert (2 || 1); //2 alert (-5 || -1); //-5
この結果を見て納得できれば論理ORの扱いはバッチリです。そうでなければ、Falsy
たちと仲良くなる必要があります。
Falsy
とは、Booleanコンテクスト(要するに真偽値に型変換する場合)にfalse
と判定される値のことです。具体的には、false
、0
、""
(空の文字列)、null
、undefined
およびNaN
です。これら以外はすべてtrue
と判定されます(それらをTruthy
と呼びます)。
したがって、先ほどの実験では0
のみがFalsy
です。論理演算子で評価するとfalse
と判定され、次の値を評価することになり、結果は1
が返るわけです。
本題
さて、ここまで説明してきましたが、結局何をやりたかったかというと、選択したテキストフレームを座標順に取得したかったのでした。
例えばこんな感じの順番でテキストフレームを取得したいけど、InDesignのallPageItems
はレイヤー的に上のものから取得するようで、下記のようなスクリプトでは末尾から取得するみたいです。
var s = app.activeDocument.pages[0].allPageItems; var temp = []; for (var i=0; i<s.length; i++){ temp.push( [s[i].geometricBounds[0], s[i].geometricBounds[1], s[i].contents]); $.writeln(s[i].contents); }
結果はこんな感じ。
二重配列をソートする関数
定規の基準を左上とした場合(左→右、上→下に座標の値が大きくなる)のソート関数を加えたものが下記になります。
var s = app.activeDocument.selection; var temp = []; for (var i=0; i<s.length; i++){ temp.push([ s[i].geometricBounds[0], s[i].geometricBounds[1], s[i].contents]); } temp.sort(function(a,b){return a[0]-b[0] || a[1]-b[1]});
sortメソッドの関数にあるreturn文の式は、テキストフレームのY座標の天を比較し(a[0]-b[0]
)、同値であればX座標を比較します(a[1]-b[1]
)。条件を追加する場合は、論理ORで式をつなぐだけです。実質的に3次以上の多次元配列もこの形式で対応することができます。
以上、二重配列のソートを使った、フレームの座標順取得でした。