インデックス配列

Flash Player 9 以降、Adobe AIR 1.0 以降

インデックス配列では、格納した一連の値に、符号なし整数値によるインデックスを指定してアクセスします。 配列内の先頭の要素は常にインデックス 0 で示され、それに続く個々の要素は順に 1 ずつ大きい数のインデックスで示されます。 ActionScript 3.0 では、Array クラスおよび Vector クラスの 2 つのクラスがインデックス配列として使用されます。

インデックス配列のインデックスに使用する数値は、符号なし 32 ビット整数です。 インデックス配列の最大サイズは 2 32 - 1(4,294,967,295)です。この最大サイズより大きい配列を作成しようとすると、ランタイムエラーが発生します。

インデックス配列の個別の要素にアクセスするには、配列アクセス( [] )演算子を使用して、アクセスする要素のインデックスの位置を指定します。例えば、次のコードでは、 songTitles という名前のインデックス配列の 1 番目の要素(インデックス 0 の要素)を表します。

songTitles[0]

配列変数名とその後に続く角括弧で囲まれたインデックスの組み合わせは、単一の識別子として機能します(つまり、変数名として可能などのような組み合わせでも使用できます)。代入ステートメントの左側に名前とインデックスを使用して、インデックス配列要素に値を割り当てることができます。

songTitles[1] = "Symphony No. 5 in D minor";

同様に、代入ステートメントの右側に名前とインデックスを使用して、インデックス配列要素の値を取得できます。

var nextSong:String = songTitles[2];

また、明示的な値を指定するのではなく、角括弧で囲まれた変数を使用することもできます(変数は、uint、正の int、正の整数の Number インスタンスなど、負でない整数値を含む必要があります)。このテクニックは、一般的に、インデックス配列内の要素を「ループ処理」して一部またはすべての要素に対して処理を実行する場合に使用されます。このテクニックを説明するコード リストを次に示します。このコードは、 oddNumbers という名前の Array オブジェクト内の各値にループを使用してアクセスします。このコードは、 trace() ステートメントを使用して、「oddNumber[ index ] = value 」の形式で各値を出力します。

var oddNumbers:Array = [1, 3, 5, 7, 9, 11]; 
var len:uint = oddNumbers.length; 
for (var i:uint = 0; i < len; i++) 
{ 
    trace("oddNumbers[" + i.toString() + "] = " + oddNumbers[i].toString()); 
}

Array クラス

インデックス配列の最初の型は、Array クラスです。Array インスタンスには、あらゆるデータ型の値を格納できます。同一の Array オブジェクトに、異なるデータ型のオブジェクトを格納できます。例えば、単一の Array インスタンスはインデックス 0 にストリング値を、インデックス 1 に Number インスタンスを、インデックス 2 に XML オブジェクトを含むことができます。

Vector クラス

ActionScript 3.0 で使用できるインデックス配列のもう 1 つの型は、Vector クラスです。Vector インスタンスは、 型指定配列です。 つまり、Vector インスタンスのすべての要素は必ず同一のデータ型を含みます。

注意: Vector クラスは、Flash Player 10 および Adobe AIR 1.5 以降で使用できます。

Vector 変数を宣言するか、または Vector オブジェクトをインスタンス化するときは、ベクターが含むことのできるオブジェクトのデータ型を明示的に指定します。指定したデータ型は、ベクターの ベース型 と呼ばれます。実行時およびコンパイル時(strict モード)には、Vector 要素の値を設定したりベクターから値を取得したりするコードはすべて検証されます。追加または取得されるオブジェクトのデータ型がベクターのベース型と一致しない場合は、エラーが発生します。

データ型の制限に加えて、Vector クラスには Array クラスと区別される次のようなその他の制限があります。

  • ベクターは高密度の配列です。Array オブジェクトは、位置 1 ~ 6 に値を含まない場合でも、インデックス 0 および 7 に値を含む場合があります。ただし、ベクターはインデックスに値(つまり、 null )を含む必要があります。

  • ベクターは、必要に応じて固定長にすることができます。固定長の場合、ベクターが含む要素数を変更することはできません。

  • ベクターの要素へのアクセスは範囲チェックが行われます。最後の要素( length - 1)より長いインデックスから値を読み取ることはできません。現在の最後のインデックスを越えて値を設定することはできません(つまり、既存のインデックスまたはインデックス [length] でのみ値を設定することができます)。

このような制限の結果として、Vector インスタンスには、エレメントがすべて単一クラスのインスタンスとなる Array インスタンスにはない、次の 3 つの主要な利点があります。

  • パフォーマンス: Array インスタンスを使用するよりも、Vector インスタンスを使用する方が、配列要素のアクセスと繰り返しが高速になります。

  • 型の安全性: strict モードでは、コンパイラーでデータ型エラーを特定できます。 このようなエラーの例としては、ベクターに不正なデータ型の値を割り当てたり、ベクターから値を読み取るときに誤ったデータ型を要求したりすることが挙げられます。実行時には、Vector オブジェクトにデータを追加するときや、このオブジェクトからデータを読み取るときにもデータ型が検証されます。ただし、 push() メソッドまたは unshift() メソッドを使用してベクターに値を追加する場合、引数のデータ型はコンパイル時にチェックされないことに注意してください。これらのメソッドを使用する場合でも、実行時には値が検証されます。

  • 信頼性:実行時範囲チェック(固定長チェック)は、Array に対する信頼性を著しく高めます。

これらの追加の制限および利点以外では、Vector クラスは Array クラスに非常によく似ています。Vector オブジェクトのプロパティとメソッドは、配列のプロパティとメソッドと似ており、ほとんどの部分は同じです。多くの場合、すべての要素が同じデータ型を持つ配列を使用するときは、Vector インスタンスが推奨されます。

配列の作成

複数のテクニックを使用して、Array インスタンスまたは Vector インスタンスを作成できます。ただし、配列の各型を作成するテクニックは、やや異なります。

Array インスタンスの作成

Array オブジェクトは、 Array() コンストラクターを呼び出すことによって、または、配列リテラルシンタックスを使用することによって作成します。

Array () コンストラクター関数には 3 つの使用方法があります。第 1 に、パラメーターを指定せずに呼び出した場合、コンストラクターは空の配列を返します。 Array クラスの length プロパティを使用すると、配列の要素が 1 つもないことを確認できます。例えば、次のコードは、 Array() コンストラクターを引数なしで呼び出しています。

var names:Array = new Array(); 
trace(names.length); // output: 0

第 2 に、1 個の数値パラメーターだけを指定した場合、 Array() コンストラクターではそのパラメーターで指定された長さの配列を作成し、各要素の値を undefined に設定します。指定する引数は、0 ~ 4,294,967,295 の値を持つ符号なし整数である必要があります。例えば、次のコードは、1 個の数値引数を指定して Array() コンストラクターを呼び出しています。

var names:Array = new Array(3); 
trace(names.length); // output: 3 
trace(names[0]); // output: undefined 
trace(names[1]); // output: undefined 
trace(names[2]); // output: undefined

第 3 に、パラメーターとして要素リストを指定した場合、コンストラクターでは、各パラメーターの値を個々の要素に設定した配列を作成します。 次のコードでは、 Array() コンストラクターに対し 3 つの引数を指定しています。

var names:Array = new Array("John", "Jane", "David"); 
trace(names.length); // output: 3 
trace(names[0]); // output: John 
trace(names[1]); // output: Jane 
trace(names[2]); // output: David

また、配列リテラルを使用して配列を作成することもできます。配列リテラルは、次の例に示すように配列変数に直接割り当てることができます。

var names:Array = ["John", "Jane", "David"];

Vector インスタンスの作成

Vector.<T>() コンストラクターを呼び出すことによって Vector インスタンスを作成するときは、ベース型を指定します。また、 Vector.<T>() グローバル関数を呼び出すことによってもベクターを作成できます。その関数は、指定されたオブジェクトを Vector インスタンスに変換します。Flash Professional CS5 以降、Flash Builder 4 以降および Flex 4 以降では、Vector インスタンスの作成にベクターリテラルシンタックスを使用することもできます。

Vector 変数(または、同様に Vector メソッドパラメーターまたは Vector メソッドの戻り型)を宣言するときは、必ず Vector 変数のベース型を指定します。また、 Vector.<T>() コンストラクターを呼び出すことによって Vector インスタンスを作成するときは、ベース型を指定します。つまり、ActionScript で Vector という用語を使用する場合はいつでも、ベース型が伴うということです。

ベクターのベース型は、型パラメーターシンタックスを使用して指定します。コードでは、 Vector という語の直後に型パラメーターが置かれます。例に示すように、このパラメーターは、ドット( . )と、その後に続く山括弧で囲まれた基本クラス名( <> )で構成されます。

var v:Vector.<String>; 
v = new Vector.<String>();

この例の最初の行では、変数 v Vector.<String> インスタンスとして宣言されます。つまり、これは、String インスタンスのみを保持できるインデックス配列を表します。2 行目では、 Vector() コンストラクターを呼び出し、同じ Vector 型(つまり、要素がすべて String オブジェクトである Vector)のインスタンスを作成します。そのオブジェクトは v に割り当てられます。

Vector.<T>() コンストラクターの使用

引数を指定しないで Vector.<T>() コンストラクターを使用すると、空の Vector インスタンスが作成されます。ベクターの length プロパティを検証することによって、Vector が空であることをテストできます。例えば、次のコードでは、引数を指定しないで Vector.<T>() コンストラクターを呼び出します。

var names:Vector.<String> = new Vector.<String>(); 
trace(names.length); // output: 0

ベクターが最初に必要とする要素の数を事前に把握している場合、ベクター内の要素数を事前に定義できます。特定の数の要素を含むベクターを作成するには、1 番目のパラメーター( length パラメーター)として要素数を渡します。Vector 要素は空にできないので、要素にはベース型のインスタンスが入力されます。ベース型が null 値を許可する参照型である場合、すべての要素は null を含みます。その他の場合、要素はすべてクラスのデフォルト値を含みます。例えば、uint 変数は null にできません。その結果、次のコードでは、7 つの要素を含みそれぞれの要素の値が 0 である ages というベクターが作成されます。

var ages:Vector.<uint> = new Vector.<uint>(7); 
trace(ages); // output: 0,0,0,0,0,0,0 

最後に、 Vector.<T>() コンストラクターを使用すると、第 2 パラメーター( fixed パラメーター)に true を渡すことによって固定長のベクターを作成することもできます。この場合、指定の数の要素を含むベクターが作成され、要素数は変更できません。ただし、固定長のベクターの要素の値を変更することはできます。

ベクターリテラルシンタックスコンストラクターの使用

Flash Professional CS5 以降、Flash Builder 4 以降および Flex 4 以降では、 Vector.<T>() コンストラクターに値リストを渡して、ベクターの初期値を指定することができます。

// var v:Vector.<T> = new <T>[E0, ..., En-1 ,]; 
// For example: 
var v:Vector.<int> = new <int>[0,1,2,];

このシンタックスには、次の情報が適用されます。

  • 末尾のカンマは省略してもかまいません。

  • 配列内の空白のアイテムはサポートされていません。 var v:Vector.<int> = new <int>[0,,2,] のようなステートメントは、コンパイラーエラーをスローします。

  • Vector インスタンスのデフォルトの長さは指定できません。指定はできませんが、デフォルトの長さは初期化リスト内のエレメントの数と同じになります。

  • Vector インスタンスを固定長にするかどうかは指定できません。代わりに、 fixed プロパティを使用します。

  • 値として渡されたアイテムが指定した型と一致しない場合、データの損失またはエラーが発生する可能性があります。次に、例を示します。
    var v:Vector.<int> = new <int>[4.2]; // compiler error when running in strict mode 
    trace(v[0]); //returns 4 when not running in strict mode

Vector.<T>() グローバル関数の使用

Vector.<T>() およびベクターリテラルシンタックスコンストラクターの他に、 Vector.<T>() グローバル関数を使用して、Vector オブジェクトを作成することもできます。 Vector.<T>() グローバル関数は変換関数です。 Vector.<T>() グローバル関数を呼び出す場合は、メソッドが返すベクターのべース型を指定します。単一のインデックス配列(Array または Vector インスタンス)を引数として渡します。次に、このメソッドは指定されたベース型で、ソース配列引数の値を含むベクターを返します。次のコードに、 Vector.<T>() グローバル関数を呼び出すシンタックスを示します。

var friends:Vector.<String> = Vector.<String>(["Bob", "Larry", "Sarah"]);

Vector.<T>() グローバル関数は、2 段階でデータ型変換を実行します。まず、Array インスタンスがこの関数に渡され、Vector インスタンスが返されます。次に、ソース配列が Array インスタンスまたは Vector インスタンスのどちらであっても、この関数はソース配列の要素をベース型の値に変換します。この変換は標準の ActionScript データ型変換規則を使用します。例えば、次のコードでは、ソース配列のストリング値を結果のベクターの整数に変換します。結果では、最初の値の小数部分( "1.5" )は切り捨てられ、数値以外の 3 番目の値( "Waffles" )は 0 に変換されます。

var numbers:Vector.<int> = Vector.<int>(["1.5", "17", "Waffles"]); 
trace(numbers); // output: 1,17,0

いずれかのソース要素を変換できない場合、エラーが発生します。

コードで Vector.<T>() グローバル関数が呼び出される場合、ソース配列の要素が指定されているベース型のサブクラスのインスタンスであるときは、結果のベクターにその要素が追加されます(エラーは発生しません)。 Vector.<T>() グローバル関数の使用は、ベース型 T を持つベクターを T のスーパークラスであるベース型を持つベクターに変換する唯一の方法です。

配列要素の挿入

インデックス配列に要素を追加する最も基本的な方法は、配列アクセス( [] )演算子を使用することです。インデックス配列要素の値を設定するには、代入ステートメントの左側に Array オブジェクトまたは Vector オブジェクトの名前とインデックス番号を使用します。

songTitles[5] = "Happy Birthday";

Array または Vector にまだそのインデックスの要素がない場合は、インデックスが作成され、そこに値が格納されます。そのインデックスに値が既にある場合は、既存の値は新しい値に置き換えられます。

Array オブジェクトでは、任意のインデックスに要素を作成できます。ただし、Vector オブジェクトでは、既存のインデックスまたは次に使用可能なインデックスにのみ値を割り当てることができます。次に使用可能なインデックスは、Vector オブジェクトの length プロパティに相当します。Vector オブジェクトに新しい要素を追加する最も安全な方法は、次のようなコードを使用する方法です。

myVector[myVector.length] = valueToAdd;

インデックス配列に要素を挿入する場合は、Array および Vector クラスにある push() unshift() 、および splice() の 3 つのメソッドを使用できます。 push() メソッドでは、配列の末尾に 1 つまたは複数の要素を追加します。したがって、 push() メソッドで挿入した最後の要素には最も大きいインデックス番号が付きます。 unshift() メソッドでは、配列の先頭に 1 つまたは複数の要素を挿入します。したがって、挿入した要素には必ずインデックス番号 0 が付きます。 splice() メソッドでは、配列内の指定されたインデックスに任意の数の要素を挿入します。

これら 3 つのメソッドについて使用例を次に示します。 太陽に近い順に惑星の名前を格納するために、 planets という名前の配列を作成します。まず、 push() メソッドを呼び出して、最初の要素 Mars を追加します。次に、 unshift() メソッドを呼び出して、配列の先頭に位置する要素 Mercury を挿入します。最後に、 splice() メソッドを呼び出して、 Mercury の後、 Mars の前に Venus および Earth を挿入します。 splice() の第 1 パラメーターとして渡している整数 1 は、挿入先をインデックス 1 の場所にするという指定です。また、 splice() 第 2 パラメーターの整数 0 は、既存の要素を 1 つも削除しないという指定です。さらに、 splice() の第 3 および第 4 パラメーターで指定している Venus Earth は挿入する要素のリストです。

var planets:Array = new Array(); 
planets.push("Mars"); // array contents: Mars 
planets.unshift("Mercury"); // array contents: Mercury,Mars 
planets.splice(1, 0, "Venus", "Earth"); 
trace(planets); // array contents: Mercury,Venus,Earth,Mars

push() および unshift() メソッドはいずれも、変更後の配列の長さを示す符号なし整数値を返します。 splice() は要素の挿入に使用した場合、空の配列を返します。これは奇異な動作のようにも見えますが、 splice() メソッドの幅広い用途を考えると理にかなっています。 splice() メソッドは配列に要素を挿入する場合だけでなく、配列から要素を削除する場合にも使用でき、削除の場合は、元の配列から削除した要素を格納した配列を返します。

注意: Vector オブジェクトの fixed プロパティが true である場合は、ベクターの要素数の合計を変更することはできません。ここで説明したテクニックを使用して固定長のベクターに新しい要素を追加しようとすると、エラーが発生します。

値の取得と配列要素の削除

インデックス配列から要素の値を取得する最も単純な方法は、配列アクセス( [] )演算子を使用する方法です。インデックス配列要素の値を取得するには、代入ステートメントの右側に Array オブジェクトまたは Vector オブジェクトの名前とインデックス番号を使用します。

var myFavoriteSong:String = songTitles[3];

要素を含まないインデックスを使用して、配列またはベクターから値の取得を試みることは可能です。その場合、Array オブジェクトでは未定義の値が返され、Vector オブジェクトでは RangeError 例外がスローされます。

要素を削除する場合は、Array および Vector クラスにある pop() shift() 、および splice() の 3 つのメソッドを使用できます。 pop() メソッドでは、配列の末尾にある 1 個の要素、つまり最も大きいインデックス番号の付いた要素を削除します。 shift() メソッドでは、配列の先頭にある 1 個の要素、つまりインデックス番号が 0 である要素を削除します。 splice() メソッドは要素の挿入にも使用できますが、第 1 引数で指定したインデックス番号が示す位置から任意の数の要素を削除する場合にも使用できます。

これら 3 つのメソッドを使用して配列インスタンスの要素を削除する例を次に示します。この例では、広い海の名前を格納するために oceans という名前の配列を作成していますが、海ではなく湖の名前がいくつか含まれているので、それらを削除します。

まず、 splice() メソッドを使用して Aral および Superior の要素を削除し、 Atlantic および Indian の要素を挿入します。 splice() の第 1 パラメーターとして渡している整数 2 は、3 番目の要素(インデックス 2)から始まる範囲を操作対象にするという指定です。また、第 2 パラメーターの整数 2 は、既存の要素を 2 つ削除するという指定です。残りのパラメーターで指定している Atlantic Indian はインデックス 2 の位置に挿入する要素のリストです。

次に、 pop() メソッドを使用して、配列の末尾に位置する要素 Huron を削除します。最後に shift() メソッドで、配列の先頭に位置する要素 Victoria を削除します。

var oceans:Array = ["Victoria", "Pacific", "Aral", "Superior", "Indian", "Huron"]; 
oceans.splice(2, 2, "Arctic", "Atlantic"); // replaces Aral and Superior 
oceans.pop(); // removes Huron 
oceans.shift(); // removes Victoria 
trace(oceans);// output: Pacific,Arctic,Atlantic,Indian

pop() および shift() メソッドはいずれも、削除した要素を返します。Array インスタンスでは、配列にはあらゆるデータ型の値を格納できるので、戻り値のデータ型は Object になっています。Vector インスタンスでは、戻り値のデータ型はベクターのベース型になっています。 splice() メソッドは、削除した値を格納した配列またはベクターを返します。 oceans 配列の例を次のように改変すると、 splice() の呼び出しで返される戻り値を新しい配列変数に割り当てることができます。

var lakes:Array = oceans.splice(2, 2, "Arctic", "Atlantic"); 
trace(lakes); // output: Aral,Superior

Array オブジェクトの要素に対して delete 演算子を使用しているコードもありますが、 delete 演算子はその要素の値を undefined に設定するだけであり、配列から要素を削除するわけではありません。例えば次のコードでは、 oceans 配列の 3 番目の要素に対して delete 演算子を使用していますが、配列の要素数はその後も変わらず 5 のままです。

var oceans:Array = ["Arctic", "Pacific", "Victoria", "Indian", "Atlantic"]; 
delete oceans[2]; 
trace(oceans);// output: Arctic,Pacific,,Indian,Atlantic 
trace(oceans[2]); // output: undefined 
trace(oceans.length); // output: 5

配列の length プロパティを使用して配列またはベクターを切り詰めることができます。インデックス配列の length プロパティを配列の現在の長さ未満に設定すると、配列は切り詰められ、 length - 1 という新しい値より大きい番号のインデックスに格納されているエレメントはすべて削除されます。例えば、 oceans 配列のすべての有効なエントリが配列の先頭に格納されていた場合、次のコードに示すように、 length プロパティを使用して配列の末尾のエントリを削除することができます。

var oceans:Array = ["Arctic", "Pacific", "Victoria", "Aral", "Superior"]; 
oceans.length = 2; 
trace(oceans); // output: Arctic,Pacific
注意: Vector オブジェクトの fixed プロパティが true である場合は、ベクターの要素数の合計を変更することはできません。ここで説明したテクニックを使用して固定長のベクターから要素を削除したり、固定長のベクターを切り詰めたりしようとすると、エラーが発生します。

配列のソート

インデックス配列要素の並び順を変更する場合は、ソートまたは順序の逆転を行う reverse() sort() sortOn() の 3 つのメソッドを使用できます。いずれのメソッドでも既存の配列が変化します。 次の表に、Array オブジェクトおよび Vector オブジェクトのこれらのメソッドとその動作をまとめます。

メソッド

配列の動作

ベクターの動作

reverse()

要素の並び順を逆転します。つまり、末尾にあった要素は先頭に、末尾の直前にあった要素は 2 番目に移動します。

配列の動作と同じです。

sort()

アルファベット順、番号順など、事前に定義した様々な方法で配列の要素をソートすることができます。また、カスタムのソートアルゴリズムを指定することもできます。

指定するカスタムのソートアルゴリズムに従って要素をソートします。

sortOn()

ソート キーとして使用する 1 つ以上のプロパティを指定して、1 つ以上の共通プロパティを含むオブジェクトをソートすることができます。

Vector クラスでは使用できません。

reverse() メソッド

reverse() メソッドは、パラメーターも戻り値もありませんが、既存の配列について現在の状態と、その並び順を逆転した状態とを切り替えるのに使用できます。次の例では、 oceans 配列に格納した海の名前を元とは逆の順序に並べ替えます。

var oceans:Array = ["Arctic", "Atlantic", "Indian", "Pacific"]; 
oceans.reverse(); 
trace(oceans); // output: Pacific,Indian,Atlantic,Arctic

sort() メソッドを使用した基本的なソート(Array クラスのみ)

Array インスタンスでは、 sort() メソッドが デフォルトのソート順 を使用して配列要素を並べ替えます。このデフォルトのソート順には、次の特性があります。

  • 大文字と小文字は区別され、大文字の方が小文字より先に並びます。 例えば、D は b よりも先に並びます。

  • ソート方向は正順です。つまり、文字コードの値の小さい文字(例:A)の方が、文字コードの値の大きい文字(例:B)よりも先に並びます。

  • 値が同等と見なされる要素は互いに隣接して並びますが、それらの間における並び順は決まっていません。

  • ソートはストリングベースで実行されます。つまり、要素は文字列に変換してから比較されます。例えば、数値の 10 は 3 よりも先に並びます。これは、ストリング「 1 」の文字コードの方がストリング「 3 」の文字コードよりも小さいためです。

大文字と小文字を区別しないソート、逆順のソート、またはアルファベット順でなく数値の大きさ順によるソートなどが必要な場合のために、Array クラスの sort() メソッドには、デフォルトのソート順に定められた各種の規則を変更する options パラメーターがあります。こうしたオプションは、次に示す Array クラスの静的定数セットによって定義されます。

  • Array.CASEINSENSITIVE :このオプションにより、ソートで大文字と小文字が無視されます。これにより、例えば小文字の b が大文字の D よりも先に並ぶようになります。

  • Array.DESCENDING :デフォルトの正順ではなく逆順でソートします。例えば、B が A よりも先に並ぶようになります。

  • Array.UNIQUESORT :同じ値を持つ複数の要素が見つかった場合にソートを中止するようにします。

  • Array.NUMERIC :数値順でソートします。例えば、3 が 10 よりも先に並ぶようになります。

これらのオプションの一部を使用した例を次に示します。 poets という名前の配列を作成し、いろいろなオプションを使用してソートを実行しています。

var poets:Array = ["Blake", "cummings", "Angelou", "Dante"]; 
poets.sort(); // default sort 
trace(poets); // output: Angelou,Blake,Dante,cummings 
 
poets.sort(Array.CASEINSENSITIVE); 
trace(poets); // output: Angelou,Blake,cummings,Dante 
 
poets.sort(Array.DESCENDING); 
trace(poets); // output: cummings,Dante,Blake,Angelou 
 
poets.sort(Array.DESCENDING | Array.CASEINSENSITIVE); // use two options 
trace(poets); // output: Dante,cummings,Blake,Angelou

sort() メソッドを使用したカスタムソート(Array クラスおよび Vector クラス)

Array オブジェクトで使用可能な基本のソートの他に、カスタムのソート規則を定義することもできます。このテクニックは、Vector クラスで使用可能な唯一の形式の sort() メソッドです。カスタムソートを定義するには、カスタムのソート関数を作成し、それを sort() メソッドに引数として渡します。

例えば、各人のフルネームを要素として格納した人名リストがあるとします。このリストを姓を基準にして並べ替える場合は、各要素を解析して姓の部分を比較するソート関数を独自に作成する必要があります。これを実現するコード例を、次に示します。この例では、カスタム関数を Array.sort() メソッドのパラメーターとして使用しています。

var names:Array = new Array("John Q. Smith", "Jane Doe", "Mike Jones"); 
function orderLastName(a, b):int 
{ 
    var lastName:RegExp = /\b\S+$/; 
    var name1 = a.match(lastName); 
    var name2 = b.match(lastName); 
    if (name1 < name2) 
    { 
        return -1; 
    } 
    else if (name1 > name2) 
    { 
        return 1; 
    } 
    else 
    { 
        return 0; 
    } 
} 
trace(names); // output: John Q. Smith,Jane Doe,Mike Jones 
names.sort(orderLastName); 
trace(names); // output: Jane Doe,Mike Jones,John Q. Smith

独自のソート関数 orderLastName() では、正規表現を使用して各要素から姓の部分を抽出し、それを比較演算に使用します。 names 配列に対する sort() メソッド呼び出しのパラメーターとして、この関数の識別子である orderLastName だけを指定しています。ソート関数に a および b の 2 つのパラメーターが渡されるのは、一度に 2 つの配列要素が処理の対象となるからです。ソート関数の戻り値は 2 つの要素の並び順を示すものであり、次の意味があります。

  • 戻り値が -1 の場合、第 1 パラメーターの a を第 2 パラメーターの b よりも先に並べることを示します。

  • 戻り値が 1 の場合、第 2 パラメーターの b を第 1 パラメーターの a よりも先に並べることを示します。

  • 戻り値が 0 の場合、2 つの要素がソートにおいて同じ順位を持つことを示します。

sortOn() メソッド(Array クラスのみ)

sortOn() メソッドは、要素がオブジェクトである Array オブジェクト用に作成されました。すべての要素のオブジェクトには、ソート用キーとなる共通のプロパティが少なくとも 1 つ含まれている必要があります。これらの条件に合わない配列に対して sortOn() メソッドを使用した場合の結果は予測不能です。

注意: Vector クラスには、 sortOn() メソッドはありません。このメソッドは、Array オブジェクトでのみ有効です。

次の例は、 poets 配列をストリング要素ではなくオブジェクト要素の配列に改変したものです。各オブジェクトには、詩人の姓と生誕年が格納されています。

var poets:Array = new Array(); 
poets.push({name:"Angelou", born:"1928"}); 
poets.push({name:"Blake", born:"1757"}); 
poets.push({name:"cummings", born:"1894"}); 
poets.push({name:"Dante", born:"1265"}); 
poets.push({name:"Wang", born:"701"});

この配列では、 born プロパティを基準として sortOn() メソッドによるソートを実行できます。 sortOn() メソッドには、 fieldName および options の 2 つのパラメーターがあります。 fieldName にはストリングを指定する必要があります。次の例では、 sortOn() にパラメーターとして「 born 」および Array.NUMERIC の 2 つを渡しています。 Array.NUMERIC オプションを指定しているのは、アルファベット順ではなく数値順で確実にソートを実行するためです。たとえ各要素に格納されている数値の桁数がすべて同じであっても、必ずこのオプションを指定するようにしておけば、後で桁数の異なる要素が追加されたとしても正常に動作します。

poets.sortOn("born", Array.NUMERIC); 
for (var i:int = 0; i < poets.length; ++i) 
{ 
    trace(poets[i].name, poets[i].born); 
} 
/* output: 
Wang 701 
Dante 1265 
Blake 1757 
cummings 1894 
Angelou 1928 
*/

元の配列を変更しないソート(Array クラスのみ)

一般に、 sort() および sortOn() メソッドを使用すると元の配列が変化します。既存の配列を変更せずにソートを実行する場合は、 options パラメーターに Array.RETURNINDEXEDARRAY 定数を含めます。このオプションを指定した場合、メソッドの戻り値はソート結果を示す新しい配列となり、元の配列の内容はそのまま維持されます。返される配列はソート後の並び順を示すインデックス番号だけを格納した単純なものであり、元の配列内の要素を格納した配列ではありません。例えば、 poets 配列について元の状態を維持したまま生誕年でのソートを実行するには、 options パラメーターに Array.RETURNINDEXEDARRAY 定数を含めます。

次の例では、戻り値のインデックス情報を indices という配列に格納し、この indices と元のままの poets を使用して詩人のリストを生誕年順に表示しています。

var indices:Array; 
indices = poets.sortOn("born", Array.NUMERIC | Array.RETURNINDEXEDARRAY); 
for (var i:int = 0; i < indices.length; ++i) 
{ 
    var index:int = indices[i]; 
    trace(poets[index].name, poets[index].born); 
} 
/* output: 
Wang 701 
Dante 1265 
Blake 1757 
cummings 1894 
Angelou 1928 
*/

配列のクエリ

Array クラスおよび Vector クラスには concat() join() slice() toString() の 4 つのメソッドがあります。これらはいずれもクエリによって配列から情報を取得するものであり、配列に変更を加えることはありません。 concat() および slice() メソッドは新しい配列を返し、 join() および toString() メソッドはストリングを返します。 concat() メソッドのパラメーターには配列または要素リストを指定します。既存の配列と、パラメーターで指定した別の配列または要素とを連結し、新しい配列を作成して返します。 slice() メソッドには、 startIndex および endIndex という 2 つのパラメーターがあります。元の配列から、これらのパラメーターで指定したインデックスの範囲を切り出し、その部分のコピーを格納した新しい配列を返します。ただし、返される範囲は startIndex が指す要素から、 endIndex が指す要素の直前までであり、 endIndex の位置にある要素は含まれません。

次の例では、既存の配列から concat() および slice() を使用して新しい配列を作成します。

var array1:Array = ["alpha", "beta"]; 
var array2:Array = array1.concat("gamma", "delta"); 
trace(array2); // output: alpha,beta,gamma,delta 
 
var array3:Array = array1.concat(array2); 
trace(array3); // output: alpha,beta,alpha,beta,gamma,delta 
 
var array4:Array = array3.slice(2,5); 
trace(array4); // output: alpha,beta,gamma

join() および toString() メソッドでは、配列の内容をストリングとして取得できます。 join() メソッドのパラメーターを指定しない場合、これら 2 つのメソッドはいずれも、すべての配列要素をカンマで区切った内容のストリングを返します。 join() メソッドには、 toString() メソッドにない delimiter というパラメーターがあり、戻り値のストリングで要素間に使用する区切り文字を指定できます。

次の例では rivers という配列を作成し、 join() および toString() を呼び出すことで、配列の内容をストリングとして取得します。 toString() メソッドはカンマ区切りの値( riverCSV )を得るため、また、 join() メソッドは + で区切った値を得るために使用しています。

var rivers:Array = ["Nile", "Amazon", "Yangtze", "Mississippi"]; 
var riverCSV:String = rivers.toString(); 
trace(riverCSV); // output: Nile,Amazon,Yangtze,Mississippi 
var riverPSV:String = rivers.join("+"); 
trace(riverPSV); // output: Nile+Amazon+Yangtze+Mississippi

join() メソッドを使用する場合には、メインの配列要素に対して指定する区切り文字に関係なく、次に示す例のように、ネストされた Array インスタンスまたは Vector インスタンスには常にカンマ区切りの値が返されることに注意する必要があります。

var nested:Array = ["b","c","d"]; 
var letters:Array = ["a",nested,"e"];  
var joined:String = letters.join("+"); 
trace(joined); // output: a+b,c,d+e