博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
C++、Java、JavaScript中迭代器的用法
阅读量:5776 次
发布时间:2019-06-18

本文共 6446 字,大约阅读时间需要 21 分钟。

hot3.png

编程思想之迭代器

什么是迭代器?

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

迭代器结构图

 

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

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

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

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

 

 

如何使用迭代器

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

 

C++中的迭代器:

void TestIterator(){	vector
vec; // 定义一容器 for(int i = 0; i < 5; i++) { vec.push_back(i*2); //添加元素 } //用迭代器访问容器中的每个元素 cout << "iterator vector:" << endl; for(vector
::iterator itr = vec.begin(); itr != vec.end(); itr ++) { cout << *itr << " "; //itr是一个指针,指向当前的元素, 所以要解引用获得元素值 } cout << endl; map
student; //创建一个map,对应学号-姓名的键值对 //添加元素 student.insert(pair
(1, "张三")); student.insert(pair
(3, "王五")); student.insert(pair
(2, "李四")); //遍历容器中的元素 cout << "iterator map:" << endl; for (map
::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
list = new ArrayList
(); list.add(4); //添加元素 list.add(3); list.add(7); //返回一个迭代器,并遍历列表中的元素 Iterator
iterator = list.iterator(); while (iterator.hasNext()) { Integer value = iterator.next(); System.out.print(value + " "); } System.out.println(); //返回ListIterator迭代器并从后往前遍历列表的元素 ListIterator
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:和

 

JavaScript中的迭代器

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

结果:

Saab

Volvo

BMW

 

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

结果:

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的迭代器请参见:

迭代器的高级应用

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

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

 

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

 

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

 

对应的实现代码如下:

对应的调用代码如下:

#include "stdafx.h"#include 
#include
#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.需要提供统一的访问接口,从而对不同的集合使用同一的算法。

 

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

转载于:https://my.oschina.net/verynix/blog/366020

你可能感兴趣的文章
云南去年有望实现151万贫困人口净脱贫
查看>>
Java架构师面试题系列整理(大全)
查看>>
延伸产业链 中国产粮大省向“精深”问发展
查看>>
消费贷用户70%月收入低于5000元 80、90后是主要人群
查看>>
2018年内蒙古外贸首次突破1000亿元
查看>>
CTOR有助于BCH石墨烯技术更上一层楼
查看>>
被遗忘的CSS
查看>>
Webpack中的sourcemap以及如何在生产和开发环境中合理的设置sourcemap的类型
查看>>
做完小程序项目、老板给我加了6k薪资~
查看>>
java工程师linux命令,这篇文章就够了
查看>>
关于React生命周期的学习
查看>>
webpack雪碧图生成
查看>>
搭建智能合约开发环境Remix IDE及使用
查看>>
Spring Cloud构建微服务架构—服务消费基础
查看>>
RAC实践采坑指北
查看>>
runtime运行时 isa指针 SEL方法选择器 IMP函数指针 Method方法 runtime消息机制 runtime的使用...
查看>>
LeetCode36.有效的数独 JavaScript
查看>>
Scrapy基本用法
查看>>
PAT A1030 动态规划
查看>>
自制一个 elasticsearch-spring-boot-starter
查看>>