Iterator について
■ Iterator について
ECMAScript 6 世代の機能です。
■イテレーターとは?
イテレーターは、反復者(繰り返し)を意味します。
リストなどから、データを順番に取得するための、共通の仕様です。
Iterator を利用すると、データの列挙方法を、統一できます。
■イテレーターを供給できるデータ構造について
配列、連想配列、単方向リスト、双方向リスト、リングリスト など
■イテレーターに対応している組み込み API について
以下の型は、Iterable なオブジェクトです。
Iterator を実装する
■ Iterable なオブジェクトについて
■ Iterable なオブジェクトとは?
イテレーターの仕様に対応し、値情報を列挙可能なオブジェクトです。
■ Iterable となる条件について
Object[Symbol.iterator]( ) :Iterator
引数 | Void | なし |
戻り値 | Iterator | 新しい Iterator オブジェクトが得られる。 |
■実装例
以下のオブジェクトは、Iterable です。
Iterable なオブジェクトを作成する
// ------------------------------------------------------------
// オブジェクトを作成する
// ------------------------------------------------------------
var my_obj = new Object();
// ------------------------------------------------------------
// [Symbol.iterator]() メソッドを実装する
// ------------------------------------------------------------
my_obj[Symbol.iterator] = function(){
var iterator = new Object();
iterator[Symbol.iterator] = function(){
return iterator;
};
iterator.next = function(){
return { done:true , value:undefined };
};
return iterator;
};
// ------------------------------------------------------------
// 新しい Iterator オブジェクトを取得する
// ------------------------------------------------------------
var iterator0 = my_obj[Symbol.iterator]();
var iterator1 = my_obj[Symbol.iterator]();
Iterable なコンストラクタを実装する
// ------------------------------------------------------------
// MyListObj コンストラクタ
// ------------------------------------------------------------
function MyListObj(){
}
// ------------------------------------------------------------
// [Symbol.iterator]() メソッドを実装する
// ------------------------------------------------------------
MyListObj.prototype[Symbol.iterator] = function (){
var iterator = new Object();
iterator[Symbol.iterator] = function(){
return iterator;
};
iterator.next = function(){
return { done:true , value:undefined };
};
return iterator;
};
// ------------------------------------------------------------
// MyListObj オブジェクトを作成する
// ------------------------------------------------------------
var my_obj = new MyListObj();
// ------------------------------------------------------------
// 新しい Iterator オブジェクトを取得する
// ------------------------------------------------------------
var iterator0 = my_obj[Symbol.iterator]();
var iterator1 = my_obj[Symbol.iterator]();
■ Iterator オブジェクトについて
■ Iterator オブジェクトとなる条件について
オブジェクトに対して、以下のメソッドを実装します。
[Symbol.iterator]() メソッドを実装します。
next() メソッドを実装します。
■ [Symbol.iterator]() メソッドについて
自身の Iterator オブジェクトを返します。
これにより、Iterator 自身も、Iterable となります。
■ next() メソッドについて
next() メソッドは、何度も呼び出されます。
戻り値から、新しい IteratorResult オブジェクトを返します。
Iterator.next( ) :IteratorResult
第01引数(略可) | * | (ここでは省略) |
戻り値 | IteratorResult | 新しい IteratorResult オブジェクトが得られる。 |
■ IteratorResult オブジェクトについて
■必要なプロパティについて
オブジェクトを作成し、以下のプロパティを追加します。
プロパティ | 型 | 解説 |
done | Boolean | 列挙が最後尾まで完了したなら true |
value | * | 今回の値情報を取得する |
■ Iterator の実装例
■リングリストの場合
リングリストに Iterator を実装する
// ------------------------------------------------------------
// RingListItem コンストラクタ
// ------------------------------------------------------------
function RingListItem(data){
this._prev = this;
this._next = this;
this.setData(data);
}
(function(){
var self = RingListItem.prototype;
// ------------------------------------------------------------
// 自身の直前にアイテムを登録
// ------------------------------------------------------------
self.attachPrev = function(item){
item.remove();
var _next = this;
var _prev = this._prev;
_prev._next = item;
_next._prev = item;
item._prev = _prev;
item._next = _next;
};
// ------------------------------------------------------------
// 自身の直後にアイテムを登録
// ------------------------------------------------------------
self.attachNext = function(item){
item.remove();
var _prev = this;
var _next = this._next;
_prev._next = item;
_next._prev = item;
item._prev = _prev;
item._next = _next;
};
// ------------------------------------------------------------
// 自身を除外
// ------------------------------------------------------------
self.remove = function(){
var _prev = this._prev;
var _next = this._next;
_prev._next = _next;
_next._prev = _prev;
this._prev = this;
this._next = this;
};
// ------------------------------------------------------------
// 直前のアイテムを取得
// ------------------------------------------------------------
self.getPrev = function(){
return this._prev;
};
// ------------------------------------------------------------
// 直後のアイテムを取得
// ------------------------------------------------------------
self.getNext = function(){
return this._next;
};
// ------------------------------------------------------------
// データを取得
// ------------------------------------------------------------
self.getData = function(){
return this.data;
};
// ------------------------------------------------------------
// データをセット
// ------------------------------------------------------------
self.setData = function(data){
this.data = data;
};
// ------------------------------------------------------------
// Iterator オブジェクトを作成する
// ------------------------------------------------------------
self[Symbol.iterator] = function(){
var item = this;
var last = this;
var done = false;
var index = 0;
var iterator = new Object();
iterator[Symbol.iterator] = function(){
return iterator;
};
iterator.next = function(){
done = (function(){
if(done) return true;
if(index == 0) return false;
var next = item.getNext();
if(next === last) return true;
if(next === item) return true;
item = next;
return false;
})();
var result = new Object();
result.done = done;
if(done){
result.value = undefined;
}else{
result.value = item.getData();
index += 1;
}
return result;
};
return iterator;
};
})();
// ------------------------------------------------------------
// RingListItem オブジェクトを作成する
// ------------------------------------------------------------
var ring_item0 = new RingListItem( "aaa" );
var ring_item1 = new RingListItem( "bbb" );
var ring_item2 = new RingListItem( "ccc" );
var ring_item3 = new RingListItem( "ddd" );
var ring_item4 = new RingListItem( "eee" );
// ------------------------------------------------------------
// リングリストを接続する
// ------------------------------------------------------------
ring_item0.attachNext( ring_item1 );
ring_item1.attachNext( ring_item2 );
ring_item2.attachNext( ring_item3 );
ring_item3.attachNext( ring_item4 );
// ------------------------------------------------------------
// for..of 文を使用して順番に列挙する
// ------------------------------------------------------------
var value;
for (value of ring_item0){
console.log( value );
}
// ------------------------------------------------------------
// Iterable なオブジェクトから配列を生成する
// ------------------------------------------------------------
var ary = Array.from(ring_item0);
// 出力テスト
console.log(ary); // [ "aaa" , "bbb" , "ccc" , "ddd" , "eee" ]
// ------------------------------------------------------------
// Iterator オブジェクトによる列挙を確認する
// ------------------------------------------------------------
// Iterator オブジェクトを生成する
var iterator = ring_item0[Symbol.iterator]();
// 値情報を順番に列挙する
var result = iterator.next();
while(!(result.done)){
console.log( result.value );
result = iterator.next();
}
■双方向リストの場合
双方向リストに Iterator を実装する
// ------------------------------------------------------------
// LinkedList コンストラクタ
// ------------------------------------------------------------
function LinkedList(){
this._list = new LinkedListItem();
}
(function(){
var self = LinkedList.prototype;
// ------------------------------------------------------------
// 最先頭にアイテムを登録
// ------------------------------------------------------------
self.attachFirst = function(item){
item.remove();
var _next = this._list;
var _prev = _next._prev;
_prev._next = item;
_next._prev = item;
item._prev = _prev;
item._next = _next;
item._null = false;
};
// ------------------------------------------------------------
// 最後尾にアイテムを登録
// ------------------------------------------------------------
self.attachLast = function(item){
item.remove();
var _prev = this._list;
var _next = _prev._next;
_prev._next = item;
_next._prev = item;
item._prev = _prev;
item._next = _next;
item._null = false;
};
// ------------------------------------------------------------
// Iterator オブジェクトを作成する
// ------------------------------------------------------------
self[Symbol.iterator] = function(){
var item = this._list;
var done = false;
var iterator = new Object();
iterator[Symbol.iterator] = function(){
return iterator;
};
iterator.next = function(){
done = (function(){
if(done) return true;
var next = item.getNext();
if(!next) return true;
item = next;
return false;
})();
var result = new Object();
result.done = done;
if(done){
result.value = undefined;
}else{
result.value = item.getData();
}
return result;
};
return iterator;
};
})();
// ------------------------------------------------------------
// LinkedListItem コンストラクタ
// ------------------------------------------------------------
function LinkedListItem(data){
this._prev = this;
this._next = this;
this._null = true;
this.setData(data);
}
(function(){
var self = LinkedListItem.prototype;
// ------------------------------------------------------------
// 自身の直前にアイテムを登録
// ------------------------------------------------------------
self.attachPrev = function(item){
if(this._null) return false;
item.remove();
var _next = this;
var _prev = this._prev;
_prev._next = item;
_next._prev = item;
item._prev = _prev;
item._next = _next;
item._null = false;
return true;
};
// ------------------------------------------------------------
// 自身の直後にアイテムを登録
// ------------------------------------------------------------
self.attachNext = function(item){
if(this._null) return false;
item.remove();
var _prev = this;
var _next = this._next;
_prev._next = item;
_next._prev = item;
item._prev = _prev;
item._next = _next;
item._null = false;
return true;
};
// ------------------------------------------------------------
// 自身を除外
// ------------------------------------------------------------
self.remove = function(){
var _prev = this._prev;
var _next = this._next;
_prev._next = _next;
_next._prev = _prev;
this._prev = this;
this._next = this;
this._null = true;
};
// ------------------------------------------------------------
// 直前のアイテムを取得
// ------------------------------------------------------------
self.getPrev = function(){
var item = this._prev;
if(item._null) return null;
return item;
};
// ------------------------------------------------------------
// 直後のアイテムを取得
// ------------------------------------------------------------
self.getNext = function(){
var item = this._next;
if(item._null) return null;
return item;
};
// ------------------------------------------------------------
// データを取得
// ------------------------------------------------------------
self.getData = function(){
return this.data;
};
// ------------------------------------------------------------
// データをセット
// ------------------------------------------------------------
self.setData = function(data){
this.data = data;
};
})();
// ------------------------------------------------------------
// LinkedList オブジェクトを作成する
// ------------------------------------------------------------
var linked_list = new LinkedList();
// ------------------------------------------------------------
// LinkedListItem オブジェクトを作成する
// ------------------------------------------------------------
var item0 = new LinkedListItem( "aaa" );
var item1 = new LinkedListItem( "bbb" );
var item2 = new LinkedListItem( "ccc" );
var item3 = new LinkedListItem( "ddd" );
var item4 = new LinkedListItem( "eee" );
// ------------------------------------------------------------
// リストを接続する
// ------------------------------------------------------------
linked_list.attachLast( item0 );
item0.attachNext( item1 );
item1.attachNext( item2 );
item2.attachNext( item3 );
item3.attachNext( item4 );
// ------------------------------------------------------------
// for..of 文を使用して順番に列挙する
// ------------------------------------------------------------
var value;
for (value of linked_list){
console.log( value );
}
// ------------------------------------------------------------
// Iterable なオブジェクトから配列を生成する
// ------------------------------------------------------------
var ary = Array.from(linked_list);
// 出力テスト
console.log(ary); // [ "aaa" , "bbb" , "ccc" , "ddd" , "eee" ]
// ------------------------------------------------------------
// Iterator オブジェクトによる列挙を確認する
// ------------------------------------------------------------
// Iterator オブジェクトを生成する
var iterator = linked_list[Symbol.iterator]();
// 値情報を順番に列挙する
var result = iterator.next();
while(!(result.done)){
console.log( result.value );
result = iterator.next();
}
Iterator オブジェクトを取得する
■ Iterator オブジェクトを取得する
■ Iterator オブジェクトを取得する
Object[Symbol.iterator]( ) :Iterator
引数 | Void | なし |
戻り値 | Iterator | 新しい Iterator オブジェクトが得られる。 |
■その他の取得用メソッドについて
別途、取得用メソッドが用意されている場合もあります。
組み込み機能の一例です。
■ Array クラス
メソッド | 説明 | |
entries() | Iterator オブジェクトを取得する(番地と値の列挙) | |
keys() | Iterator オブジェクトを取得する(番地の列挙) | |
values() | Iterator オブジェクトを取得する(値の列挙) | * |
■ Map クラス
メソッド | 説明 | |
entries() | Iterator オブジェクトを取得する(キーと値の列挙) | * |
keys() | Iterator オブジェクトを取得する(キーの列挙) | |
values() | Iterator オブジェクトを取得する(値の列挙) |
■ Set クラス
■近似メソッドについて(自身が Iterable ではない場合)
Iterator オブジェクトではなく、Array オブジェクトが得られます。
Array オブジェクトは、Iterable です。
■ Object クラス
メソッド | 説明 | |
Object.entries() | Array オブジェクトを取得する(キーと値の列挙) | |
Object.keys() | Array オブジェクトを取得する(キーの列挙) | |
Object.values() | Array オブジェクトを取得する(値の列挙) |
Iterator を使ってデータを列挙する
■値情報を順番に列挙する(Iterator オブジェクト)
■ Iterator オブジェクトを取得する
こちらで解説しています。
■ Iterator オブジェクトから、値情報を列挙する
next() メソッドを使用します。
next() メソッドを、何度も呼び出す事で、値情報を順番に取り出せます。
Iterator.next( ) :IteratorResult
第01引数(略可) | * | (ここでは省略) |
戻り値 | IteratorResult | 新しい IteratorResult オブジェクトが得られる。 |
■IteratorResult オブジェクトについて
プロパティ | 型 | 解説 |
done | Boolean | 列挙が最後尾まで完了したなら true |
value | * | 今回の値情報を取得する |
■使用例
Iterator オブジェクトと next() メソッドの動作を確認する
// ------------------------------------------------------------
// 配列を作成する
// ------------------------------------------------------------
var ary = ["aaa" , "bbb" , "ccc" , "ddd" , "eee"];
// ------------------------------------------------------------
// Iterator オブジェクトを取得(値の列挙)
// ------------------------------------------------------------
var iterator = ary[Symbol.iterator]();
// ------------------------------------------------------------
// 出力テスト
// ------------------------------------------------------------
console.log( iterator.next() ); // { done:false , value:"aaa" }
console.log( iterator.next() ); // { done:false , value:"bbb" }
console.log( iterator.next() ); // { done:false , value:"ccc" }
console.log( iterator.next() ); // { done:false , value:"ddd" }
console.log( iterator.next() ); // { done:false , value:"eee" }
console.log( iterator.next() ); // { done:true , value:undefined }
console.log( iterator.next() ); // { done:true , value:undefined }
console.log( iterator.next() ); // { done:true , value:undefined }
while 文を使って、値情報を順番に取得する
// ------------------------------------------------------------
// 配列を作成する
// ------------------------------------------------------------
var ary = ["aaa" , "bbb" , "ccc" , "ddd" , "eee"];
// ------------------------------------------------------------
// Iterator オブジェクトを取得(値の列挙)
// ------------------------------------------------------------
var iterator = ary[Symbol.iterator]();
// ------------------------------------------------------------
// 値情報を順番に列挙する
// ------------------------------------------------------------
var result = iterator.next();
while(!(result.done)){
console.log( result.value );
result = iterator.next();
}
■値情報を順番に列挙する(for..of 文)
for..of 文を使用すると、値情報を順番に列挙できます。
of 文の次に、Iterable なオブジェクトを指定します。
■使用例
for..of 文を使って、値情報を順番に取得する(Array オブジェクトの場合)
// ------------------------------------------------------------
// 配列を作成する
// ------------------------------------------------------------
var ary = ["aaa" , "bbb" , "ccc" , "ddd" , "eee"];
// ------------------------------------------------------------
// 値情報を順番に列挙する(Iterable なオブジェクトを指定)
// ------------------------------------------------------------
var value;
for(value of ary){
console.log( value );
}
for..of 文を使って、値情報を順番に取得する(Map オブジェクトの場合)
// ------------------------------------------------------------
// Map オブジェクトを作成する
// ------------------------------------------------------------
var map = new Map();
// ------------------------------------------------------------
// 適当なデータを格納する
// ------------------------------------------------------------
map.set( "aaa" , "あ" );
map.set( "bbb" , "い" );
map.set( "ccc" , "う" );
map.set( "ddd" , "え" );
map.set( "eee" , "お" );
// ------------------------------------------------------------
// 値情報を順番に列挙する
// ------------------------------------------------------------
var key,value;
for([key,value] of map){
console.log( key , value );
}
■ Iterator オブジェクトを指定した場合
Iterator は、Iterable の条件を満たしています。
Iterator の、[Symbol.iterator]() メソッドは、自身の参照を返します。
新しい Iterator を生成するわけではありません。
よって、for..of 文に Iterator を渡すと、中身が更新されます。
for..of 文に Iterator を指定した場合の動作を確認する
// ------------------------------------------------------------
// 配列を作成する
// ------------------------------------------------------------
var ary = ["aaa" , "bbb" , "ccc" , "ddd" , "eee"];
// ------------------------------------------------------------
// Iterator オブジェクトを取得
// ------------------------------------------------------------
var iterator = ary[Symbol.iterator]();
// ------------------------------------------------------------
// 値情報を順番に列挙する(Iterator を渡すと中身が更新される)
// ------------------------------------------------------------
var value;
for(value of iterator){
console.log( value );
}
console.log( iterator.next() ); // { done:true , value:undefined }
■すべての値情報をまとめて取得する(Array オブジェクトを取得)
Array.from() メソッドを使用します。
Array.from( iterable ) :Array
第01引数 | * | Iterable なオブジェクトを指定 |
戻り値 | Array | 新しい Array オブジェクトが得られる |
■使用例
文字列から、Array オブジェクトを生成する
// ------------------------------------------------------------
// 適当な文字列を用意
// ------------------------------------------------------------
var str = "あいうえお";
// ------------------------------------------------------------
// 文字列から、Array オブジェクトを生成する
// ------------------------------------------------------------
var ary = Array.from(str);
// 出力テスト
console.log(ary); // [ "あ" , "い" , "う" , "え" , "お" ]
■すべての値情報をまとめて取得する(Map オブジェクトを取得)
Map() コンストラクタを使用します。
new Map( iterable ) :Map
第01引数 | * | Iterable なオブジェクトを指定。値情報は、[ "キー" , 値 ] |
戻り値 | Map | 新しい Map オブジェクトが得られる |
■使用例
ジェネレーターから、Map オブジェクトを生成する
// ------------------------------------------------------------
// ジェネレーター関数(オブジェクトから [ "キー" , 値 ] を列挙)
// ------------------------------------------------------------
function* Object_Entries(obj){
var key;
for(key in obj){
var value = obj[key];
yield [ key , value ];
}
};
// ------------------------------------------------------------
// 適当なオブジェクトを用意
// ------------------------------------------------------------
var dictionary = {
"aaa":"あ",
"bbb":"い",
"ccc":"う",
"ddd":"え",
"eee":"お"
};
// ------------------------------------------------------------
// ジェネレーターを生成
// ------------------------------------------------------------
var generator = Object_Entries(dictionary);
// ------------------------------------------------------------
// ジェネレーターから、Map オブジェクトを生成する
// ------------------------------------------------------------
var map = new Map(generator);
// 出力テスト
console.log(map); // { "aaa":"あ" , "bbb":"い" , "ccc":"う" , "ddd":"え" , "eee":"お" }