6.4 Map的读写
当从Map读取数据时,可以使用当初定义时所用的键名。为Map写入新的条目时需要用户提供每一条的键名和数值。
需要注意的是:对于大型Map,keys和values所涉及的函数会占用大量的内存,因为它们的输出是元胞数组。
1.Map的读取
在创建并填充好Map对象之后,用户就可以用它来进行数据的存储和寻访了。一般情况下,使用Map和使用一个数组类似,除非用户使用的是整数下标索引。寻访指定键(keyN)所对应的值(valueN)使用的一般方法如下。如果键名是一个字符串,应注意使用单引号将键名括起来。
valueN = mapObj(keyN);
【例3-32】 Map的读取示例。
用户可以通过使用正确的键名访问任何Map中的单个值。本例在上例建立的机票Map上进行讲解。
>> passenger = ticketMap('2R175')
passenger =
James Enright
如果要查找持有机票编号为A479GY的乘客,可以使用如下命令:
>> sprintf(' Would passenger %s please come to the desk?\n', ...
ticketMap('A479GY'))
ans =
Would passenger Sarah Latham please come to the desk?
如果需要同时对多个键进行寻访,可以使用values函数,在一个元胞数组中对键名进行指定。
>> values(ticketMap, {'2R175', 'B7398'})
ans =
'James Enright' 'Carl Haynes'
需要指出的是:用户不能像在其他数据类型中那样使用冒号运算符。例如,下面的表达式将会产生错误:
>> ticketMap('2R175':'B7398')
Warning: Colon operands must be real scalars.
??? Error using ==> subsref
The specified key is not present in this container.
2.添加Keys/Values对
和数组类型不同,Map中的每个条目都包括两项:值和键。当用户向一个Map中写入新值的时候,则必须同时提供键名,这个键名的类型必须和Map中的其他键一致。
可以使用如下命令向Map中写入新的元素。
existingMapObj(newKeyName) = newValue;
【例3-33】 Map的写入示例。继上例,向ticketMap添加两个新的条目,并验证Map中的keys/values对数目。
>> ticketMap('947F4') = 'Susan Spera';
>> ticketMap('417R93') = 'Patricia Hughes';
>> ticketMap.Count
ans =
6
查看Map ticketMap中的键和值。
>> keys(ticketMap)
ans =
'2R175' '417R93' '947F4' 'A479GY' 'B7398' 'NZ1452'
>> values(ticketMap)
ans =
Columns 1 through 3
'James Enright' 'Patricia Hughes' 'Susan Spera'
Columns 4 through 6
'Sarah Latham' 'Carl Haynes' 'Bradley Reid'
3.Map的合并
用户可以通过Map合并的方式向已有的Map中写入一组keys/values对。Map对象的合并和MATLAB中的其他数据类型不同,MATLAB返回的是一个包括源Map对象的keys/values对的单Map对象。
Map合并的规则如下。
(1)只有包括垂直向量的Map对象才可以。不能创建一个m×n的数组或者一个水平向量s。所以,vertcat函数支持Map对象,但是horzcat函数不支持。
(2)所有源Map对象的键必须是同一种类型。
(3)可以将具有不同数目keys/values对的Map对象合并,返回的结果是一个包括源Map对象的keys/values对的单Map对象。
(4)Map合并结果中不包括源Map对象中键名重复的keys/values对。
【例3-34】 Map对象的合并示例。
>> tMap1 = containers.Map({'2R175', 'B7398', 'A479GY'}, ...
{'James Enright', 'Carl Haynes', 'Sarah Latham'});
>> tMap2 = containers.Map({'417R93', 'NZ1452', '947F4'}, ...
{'Patricia Hughes', 'Bradley Reid', 'Susan Spera'});
>> ticketMap = [tMap1; tMap2]; % Map对象的合并
>> ticketMap.Count % 查看合并之后的keys/values对数目
ans =
6
>> keys(ticketMap)
ans =
'2R175' '417R93' '947F4' 'A479GY' 'B7398' 'NZ1452'
>> values(ticketMap)
ans =
Columns 1 through 3
'James Enright' 'Patricia Hughes' 'Susan Spera'
Columns 4 through 6
'Sarah Latham' 'Carl Haynes' 'Bradley Reid'
【例3-35】 具有重复键名的Map对象的合并示例。
在本例中,对象m1和m2都有键名8。在Map m1中,8是值C对应的一个键;而在m2中,8是值X对应的键。
>> m1 = containers.Map({1, 5, 8}, {'A', 'B', 'C'});
>> m2 = containers.Map({8, 9, 6}, {'X', 'Y', 'Z'});
下面将两个Map对象进行合并:
>> m3 = [m1; m2];
合并以后的结果如下:
>> keys(m3)
ans =
[1] [5] [6] [8] [9]
>> values(m3)
ans =
'A' 'B' 'Z' 'X' 'Y'
>> m4 = [m2; m1]; % m4与m3的合并顺序不同
>> keys(m4)
ans =
[1] [5] [6] [8] [9]
>> values(m4)
ans =
'A' 'B' 'Z' 'C' 'Y' % 键8所对应的值是不同的
值得注意的是在具有重复键名的时候,合并顺序不同,得到的结果也不同。得到的结果将保存重复键名靠后位置所对应的值。
6.5 Map中key和value的修改
除了对Map对象进行读写、添加与合并之外,用户还可以删除keys/values对,修改任何值或者键。
1.从Map对象中删除keys/values对
函数remove用于从Map对象中删除keys/values对。在调用这个函数的时候,需要指定Map对象的名字和需要删除的键名,MATLAB会在命令运行之后删除指定的键名和其相对应的值。
函数remove的语法结构为:
remove('mapName', 'keyname');
【例3-36】 在例3-34的基础上,从Map对象中删除keys/values对示例。
>> remove(ticketMap, 'NZ1452'); % 删除键NZ1452对应的条目
>> keys(ticketMap)
ans =
'2R175' '417R93' '947F4' 'A479GY' 'B7398'
>> values(ticketMap)
ans =
Columns 1 through 3
'James Enright' 'Patricia Hughes' 'Susan Spera'
Columns 4 through 5
'Sarah Latham' 'Carl Haynes'
2.修改Values
通过简单的覆盖,用户就可以对Map中的值进行修改。
【例3-37】 Map中的值修改示例。
为方便起见,此处在上例的基础上进行修改。持有机票A479GY的乘客名字为Sarah Latham:
>> ticketMap('A479GY')
ans =
Sarah Latham
修改乘客的名字为Anna Latham,可以通过以下命令来实现:
>> ticketMap('A479GY') = 'Anna Latham';
可以输入以下命令来验证修改的结果:
>> ticketMap('A479GY')
ans =
'Anna Latham';
3.修改Keys
如果需要在保持值不变的情况下对键名进行修改,首先需要删除键名和对应的值,然后再添加一个有正确键名的新条目。
【例3-38】 Map中的键修改示例。
在上例的基础上,修改乘客James Enright的机票号码:
>> remove(ticketMap, '2R175'); % 删除原有的机票号码条目
>> ticketMap('2S185') = 'James Enright'; % 添加新的机票号码条目
>> k = keys(ticketMap);
>> v = values(ticketMap);
>> str1 = ' ''%s'' has been assigned a new\n';
>> str2 = ' ticket number: %s.\n';
>> fprintf(str1, v{1}),fprintf(str2, k{1}) % 显示修改的结果
'James Enright' has been assigned a new
ticket number: 2S185.
4.修改副本Map
因为ticketMap是一个句柄对象,所以用户在通过复制这个Map,创建Map副本时的操作需要非常小心。在对Map对象创建副本的时候,实际上只是创建了同一个对象的新句柄而已,所有的对于新句柄的操作都会影响到原始Map对象。
【例3-39】 创建ticketMap的一个副本,副本中写入新条目。注意原始对象的改变。
>> copiedMap = ticketMap; % 创建副本
>> copiedMap('AZ12345') = 'unidentified person'; % 在副本中添加新条目
>> ticketMap('AZ12345') % 查看原始Map对象
ans =
unidentified person
通过查看原始Map对象可以发现,通过对副本的修改,原始对象也发生了改变。
>> remove(ticketMap, 'AZ12345'); % 删除原始对象中的条目
>> keys(ticketMap)
ans =
'2S185' '417R93' '947F4' 'A479GY' 'B7398'
>> keys(copiedMap)
ans =
'2S185' '417R93' '947F4' 'A479GY' 'B7398'
>> clear copiedMap; % 删除副本
>> keys(ticketMap) % 并没有删除原始Map对象
ans =
'2S185' '417R93' '947F4' 'A479GY' 'B7398'
6.6 映射其他数据类型
在Map容器中存储其他数据类型是非常常见的,例如结构数组或者元胞数组。但是,当Map中存储的是双精度、字符串、整数或者逻辑值的时候,内存的使用效率则最高。
1.映射到结构数组
下面的例子将座位号映射到包含乘客名字的结构数组。
【例3-40】 映射到结构数组示例。
首先需要创建一个包括乘客相关信息的结构数组。
>> s1.ticketNum = '2S185'; s1.destination = 'Barbados';
>> s1.reserved = '06-May-2008'; s1.origin = 'La Guardia';
>> s2.ticketNum = '947F4'; s2.destination = 'St. John';
>> s2.reserved = '14-Apr-2008'; s2.origin = 'Oakland';
>> s3.ticketNum = 'A479GY'; s3.destination = 'St. Lucia';
>> s3.reserved = '28-Mar-2008'; s3.origin = 'JFK';
>> s4.ticketNum = 'B7398'; s4.destination = 'Granada';
>> s4.reserved = '30-Apr-2008'; s4.origin = 'JFK';
>> s5.ticketNum = 'NZ1452'; s5.destination = 'Aruba';
>> s5.reserved = '01-May-2008'; s5.origin = 'Denver';
将5个座位号映射到这些结构数组,可以使用以下命令:
>> seatingMap = containers.Map( ...
{'23F', '15C', '15B', '09C', '12D'}, ...
{s5, s1, s3, s4, s2});
使用这个Map对象,可以查找到预定了09C座位的乘客信息。
>> seatingMap('09C')
ans =
ticketNum: 'B7398'
destination: 'Granada'
reserved: '30-Apr-2008'
origin: 'JFK'
>> seatingMap('15B').ticketNum
ans =
A479GY
结合上面例子中的Map对象,用户可以查找到预定了该座位的乘客姓名。
>> passenger = ticketMap(seatingMap('15B').ticketNum)
passenger =
Anna Latham
2.映射到元胞数组
和结构数组类似,用户可以将Map对象映射到一个元胞数组。本节继续在前面机票例子的基础上对此进行介绍。一些乘客在航空公司开有"frequent flyer"账号,将这些乘客的名字映射到他们已经飞行的里程数和剩余里程数,可以使用如下命令:
>> accountMap = containers.Map( ...
{'Susan Spera','Carl Haynes','Anna Latham'}, ...
{{247.5, 56.1}, {0, 1342.9}, {24.6, 314.7}});
使用Map对乘客的账户信息进行寻访,可以使用如下命令:
>> name = 'Carl Haynes';
>> acct = accountMap(name);
>> fprintf('%s has used %.1f miles on his/her account,\n', ...
name, acct{1})
>> fprintf(' and has %.1f miles remaining.\n', acct{2})
Carl Haynes has used 0.0 miles on his/her account,
and has 1342.9 miles remaining.