C++、Java、JavaScript中迭代器的用法

原创 2015年01月06日 23:19:49

编程思想之迭代器



什么是迭代器?

迭代器(Iterator)是按照一定的顺序对一个或多个容器中的元素从前往遍历的一种机制,比如for循环就是一种最简单的迭代器,对一个数组的遍历也是一种的迭代遍历的过程。GOF给出的定义为:提供一种方法访问一个容器(container)对象中各个元素,而又不需暴露该对象的内部细节。迭代器有时也称为枚举器(Enumerator),其结构图如下:

迭代器结构图

 

迭代器其实就是维护一个当前的指针,这个指针可以指向当前的元素,可以返回当前所指向的元素,可以移到下一个元素的位置,通过这个指针可以遍历容器的所有元素。迭代器一般至少会有以下几种方法:

First(); //将指针移至第一个位置或获得第一个元素

GetCurrent(); //获得当前所指向的元素

MoveNext(); //移至下一个元素

 

 

如何使用迭代器

既然迭代器是封装里面的实现细节,对外提供方便访问容器元素的接口,那我们就先从使用的角度认识迭代器,看看在各种语言下迭代器是如何使用的。

 

C++中的迭代器:

void TestIterator()
{
	vector<int> vec;			// 定义一容器
	for(int i = 0; i < 5; i++)
	{
		vec.push_back(i*2);		//添加元素
	}
	//用迭代器访问容器中的每个元素
	cout << "iterator vector:" << endl;
	for(vector<int>::iterator itr = vec.begin(); itr != vec.end(); itr ++)
	{
		cout << *itr << "   ";	//itr是一个指针,指向当前的元素, 所以要解引用获得元素值
	}
	cout << endl;


	map<int, string> student;	//创建一个map,对应学号-姓名的键值对
	//添加元素
	student.insert(pair<int, string>(1, "张三"));
	student.insert(pair<int, string>(3, "王五"));
	student.insert(pair<int, string>(2, "李四"));
	//遍历容器中的元素
	cout << "iterator map:" << endl;
	for (map<int, string>::iterator itr = student.begin(); itr != student.end(); itr ++)
	{
		cout << itr->first << "-->" << itr->second << endl;
	}
}

结果:


iterator vector:

0   2   4   6   8

iterator map:

1-->张三

2-->李四

3-->王五

 

c++中的容器(如vector、map、list、set等)一般会提供四个迭代器:

iterator:正向迭代,从前往后遍历,可修改元素的值

const_iterator:正向常量迭代,但不能修改元素的值,因为指向的是const的引用

reverse_iterator:反向迭代,从后往前遍历,可修改元素的值

const_reverse_iterator:反向常量迭代,但不能修改元素的值,因为指向的是const的引用

每一种迭代器都提供一对首尾位置的标志begin和end,其关系如下:

迭代器类型

开始位置标志

末尾位置标志

说明

iterator

begin()

end()

正向迭代

const_iterator

cbegin()

cend()

正向常量迭代

reverse_iterator

rbegin()

rend()

反向迭代

const_reverse_iterator

crbegin()

crend()

反向常量迭代

 

对应的示意图如下:


 图1:正常的迭代

 

 图2:常量值的迭代

 

 

Java中的迭代器:

public static void testIterator() {
	//创建一个列表
	List<Integer> list = new ArrayList<Integer>();
	list.add(4);	//添加元素
	list.add(3);
	list.add(7);

	//返回一个迭代器,并遍历列表中的元素
	Iterator<Integer> iterator = list.iterator();
	while (iterator.hasNext()) {
		Integer value = iterator.next();
		System.out.print(value + "    ");
	}
	System.out.println();

	//返回ListIterator迭代器并从后往前遍历列表的元素
	ListIterator<Integer> listIterator = list.listIterator(list.size());

	System.out.println("ListIterator:");
	while (listIterator.hasPrevious()) {
		Integer value = listIterator.previous();
		System.out.print(value + "    ");
	}
	System.out.println();
}

结果:

Iterator begin to end:

4    3    7    

ListIterator end to begin:

7    3    4    

 

Java中的List接口及其实现类可以通过iterator()返回Iterator,或通过listIterator()和listIterator(int index) 返回ListIterator。

Iterator和ListIterator都是迭代器,ListIterator继承自Iterator。Iterator只能对列表进行遍历,且只能从前往后遍历,ListIterator可以修改列表,且可以选择往前或往后遍历。关于Iterator和ListIterator更详细的说明请参见官方API:IteratorListIterator

 

JavaScript中的迭代器

JavaScript中表示容器的是Array类型,标准并没有给出对应的迭代器的说明和实现,但我们可以自己实现一个简单的迭代器的功能:

<script type="text/javascript">

	//创建一个迭代器,传入的必须是Array类型的数据
	function makeIterator(array) {
		var index = 0;

		return {
			hasNext: function () {
				return index < array.length;
			},
			
			next: function () {
				return this.hasNext ? array[index++] : null;
			},
			
			current: function () {
				return array[index];
			}
		};
	}
		
	//创建一个数组并赋值
	var mycars=new Array();
	mycars[0]="Saab";
	mycars[1]="Volvo";
	mycars[2]="BMW";
	//将数组mycars生成一个迭代器,并通过迭代器遍历数据元素
	var iterator = makeIterator(mycars);
	while (iterator.hasNext()) {
		document.write(iterator.next() + '<br>');
	}
</script>

结果:

Saab

Volvo

BMW

 

mozilla提供的JavaScript 1.7已经添加了迭代器的功能,但现在只能在Firefox浏览器上才有用。如:

<script type="application/javascript;version=1.7">
	var lang = { name: 'JavaScript', birthYear: 1995, age: 19 };
    //生成一个迭代器
	var itr = Iterator(lang);
	document.write('key-value:' + '<br>');
	for(var key in itr){
		document.write(key + '<br>');
	}
	
	//这个迭代器遍历每一个key值
	var itr2 = Iterator(lang, false);
	document.write('key:' + '<br>');
	for(var key in itr2){
		document.write(key + '<br>');
	}
	
	//这个迭代器遍历每一个索引和值
	var arrs = ['JavaScript', 'Python', 'Haskell'];
	var itr3 = Iterator(arrs, false);
	document.write('index-value:' + '<br>');
	for(let [i, value] in itr3){
		document.write(i + ':' + value + '<br>');
	}
</script>

结果:

key-value:

name,JavaScript

birthYear,1995

age,19

key:

name,JavaScript

birthYear,1995

age,19

index-value:

0:JavaScript

1:Python

2:Haskell

 

更多关于JavaScript 1.7的迭代器请参见:Iterators and Generators



迭代器的高级应用

在上面一小节“JavaScript中的迭代器”中,已经对Array数组实现了自己定义的迭代器。以上讲述的迭代器基本都是集合内部的元素具有相同的数据类型,但实际的开发过程中可能会有更复杂的容器结构,假设有如下的需要:

一个公司有多个部门,每个部门有多个人组成,这些人中有开发人员,有测试人员,和与项目相关的其它人员,其结构如下:

 

现在要遍历这个公司的所有开发人员,遍历这个公司的所有测试人员。

 

针对这个需求,我们可以创建一个定制化的迭代器来遍历一个公司所有人员,也可以传入员工类型来遍历指定类型的员工,其类的结构图如下:

 

对应的实现代码如下:

git@code.csdn.net:luoweifu/iteratortest.git

对应的调用代码如下:

#include "stdafx.h"
#include <string>
#include <iostream>
#include "Person.h"
#include "Department.h"
#include "Company.h"
#include "Enumerator.h"

int _tmain(int argc, _TCHAR* argv[])
{
	Company company("Apabi");
	Department* pDepartMent1 = new Department("开发1部");
	Department* pDepartMent2 = new Department("开发2部");
	Department* pDepartMent3 = new Department("内核研发部");
	company.AddDepartment(pDepartMent1);
	company.AddDepartment(pDepartMent2);
	company.AddDepartment(pDepartMent3);
	int empId = 1;

	Person* pPerson11 = new Developer(empId++, "Developer11", "C++", "智慧城市");
	Person* pPerson12 = new Developer(empId++, "Developer12", "Java", "智慧城市");
	Person* pPerson13 = new Developer(empId++, "Developer13", "Java", "智慧城市");
	Person* pPerson14 = new Developer(empId++, "Developer14", "JavaScript", "智慧城市");
	Person* pPerson15 = new Tester(empId++, "Tester15", "LoadRunner");
	Person* pPerson16 = new Tester(empId++, "Tester16", "黑盒测试");
	cout << pPerson16->GetPersonType() << endl;
	pDepartMent1->AddPerson(pPerson11);
	pDepartMent1->AddPerson(pPerson12);
	pDepartMent1->AddPerson(pPerson13);
	pDepartMent1->AddPerson(pPerson14);
	pDepartMent1->AddPerson(pPerson15);
	pDepartMent1->AddPerson(pPerson16);

	Person* pPerson21 = new Developer(empId++, "Developer21", "IOS", "Mobile");
	Person* pPerson22 = new Developer(empId++, "Developer22", "Android", "Mobile");
	Person* pPerson23 = new Tester(empId++, "Tester23", "LoadRunner");
	Person* pPerson24 = new Tester(empId++, "Tester24", "TestIn");
	pDepartMent2->AddPerson(pPerson21);
	pDepartMent2->AddPerson(pPerson22);
	pDepartMent2->AddPerson(pPerson23);
	pDepartMent2->AddPerson(pPerson24);

	Person* pPerson31 = new Developer(empId++, "Developer31", "C++", "CEBX内核");
	Person* pPerson32 = new Developer(empId++, "Developer32", "C++", "CEBX内核");
	Person* pPerson33 = new Developer(empId++, "Developer33", "C++", "CEBX内核");
	Person* pPerson34 = new Developer(empId++, "Developer34", "C++", "CEBX内核");
	Person* pPerson35 = new Tester(empId++, "Tester35", "LoadRunner");
	pDepartMent3->AddPerson(pPerson31);
	pDepartMent3->AddPerson(pPerson32);
	pDepartMent3->AddPerson(pPerson33);
	pDepartMent3->AddPerson(pPerson34);
	pDepartMent3->AddPerson(pPerson35);
	
	//遍历所有开发者
	cout << "遍历所有开发者:" << endl;
	Enumerator* pEnumerator1 = company.GetEnumerator(PERSON_DEVELOPER);
	while(pEnumerator1->MoveNext())
	{
		Person* pPerson = pEnumerator1->Current();
		if (pPerson)
		{
			pPerson->showInfo();
		}
	}
	delete pEnumerator1;

	//遍历所有测试人员
	cout << "遍历所有测试人员:" << endl;
	Enumerator* pEnumerator2 = company.GetEnumerator(PERSON_TESTER);
	while(pEnumerator2->MoveNext())
	{
		Person* pPerson = pEnumerator2->Current();
		if (pPerson)
		{
			pPerson->showInfo();
		}
	}
	delete pEnumerator2;

	//遍历公司所有员工
	cout << "遍历公司所有员工:" << endl;
	Enumerator* pEnumerator3 = company.GetEnumerator(PERSON_TYPE_NONE);
	while(pEnumerator3->MoveNext())
	{
		Person* pPerson = pEnumerator3->Current();
		if (pPerson)
		{
			pPerson->showInfo();
		}
	}
	delete pEnumerator3;

	return 0;
}

这样就使得代码简洁易懂易读。

 

 

迭代器的应用场景

1.集合的内部结构复杂,不想暴露对象的内部细节,只提供精简的访问方式;

2.需要提供统一的访问接口,从而对不同的集合使用同一的算法。

 


=====================编程思想系列文章回顾=====================

编程思想之递归

编程思想之回调



版权声明:本文为博主原创文章,未经博主允许不得用于任何商业用途,转载请注明出处。

c++迭代器介绍

迭代器的简介 (1):迭代器类似于指针类型,它也提供了对对象的间接访问。 (2):指针是c语言中就有的东西,迭代器是c++中才有的,指针用起来灵活高效,迭代器功能更丰富些。 (3):迭代器提供一...

c++从零开始学起(关于迭代器的使用)

迭代器是c++中用得比较多的一种访问机制。它定义了所有标准库容器以及vector、string等类型的迭代。 1、begin和end的使用:begin负责返回第一个元素的迭代器,end则返回容器最后一...

C/C++迭代器使用详解

迭代器是一种检查容器内元素并遍历元素的数据类型。

【C++】:STL迭代器使用详解,很好很详细

写在前面,迭代器这种东西,就是为了使访问简单!! 容器::iterator iter; for(iter= 容器.begin();iter!=容易.end();iter++){ coutfirst等等...

C++标准模板库(STL)迭代器的原理与实现

迭代器(iterator)是一种抽象的设计理念,本文探讨了迭代器的作用与原理,实现了简单的迭代器,并采用trait编程技巧编写了简单算法验证。...

C++迭代器(iterator)的简单使用

迭代器提供对一个容器中的对象的访问方法,并且定义了容器中对象的范围。迭代器就如同一个指针。事实上,C++的指针也是一种迭代器。但是,迭代器不仅仅是指针,因此你不能认为他们一定具有地址值。例如,一个数组...
  • Icarus_
  • Icarus_
  • 2016年03月20日 20:41
  • 2457

C++ 迭代器

C++ 迭代器 基础介绍 迭代器提供对一个容器中的对象的访问方法,并且定义了容器中对象的范围。迭代器就如同一个指针。事实上,C++的指针也是一种迭代器。但是,迭代器不仅仅是指针,因此你不能认为他们一定...

C++迭代器

C++迭代器 一、迭代器简介 通俗的说,迭代器就是可以代替使用下标运算符访问string等对象的另一种通用机制。 迭代器类型有两个成员分别是begin和end,end返回的迭代器往往被称作尾后迭...

c++迭代器的使用与简介

c++迭代器的使用与简介     除了使用下标来访问vector对象的元素外,标准库还提供了另一种检测元素的方法:使用迭代器(iterator)。迭代器是一种允许程序员检查容器内...

C++之itertor迭代器

一、迭代器简介   迭代器是一种检查容器内元素并遍历元素的数据类型。   标准库为每一种标准容器定义了一种迭代器类型。迭代器类型提供了比下标操作更通用化的方法:所有的标准库容器都定义了相应的迭代器...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:C++、Java、JavaScript中迭代器的用法
举报原因:
原因补充:

(最多只允许输入30个字)