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'))

Would passenger Sarah Latham please come to the desk?

如果需要同时对多个键进行寻访,可以使用values函数,在一个元胞数组中对键名进行指定。

>> values(ticketMap, {'2R175', 'B7398'})

'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.

和数组类型不同,Map中的每个条目都包括两项:值和键。当用户向一个Map中写入新值的时候,则必须同时提供键名,这个键名的类型必须和Map中的其他键一致。

可以使用如下命令向Map中写入新的元素。

existingMapObj(newKeyName) = newValue;

【例3-33】  Map的写入示例。继上例,向ticketMap添加两个新的条目,并验证Map中的keys/values对数目。

>> ticketMap('947F4') = 'Susan Spera';

>> ticketMap('417R93') = 'Patricia Hughes';

>> ticketMap.Count

查看Map ticketMap中的键和值。

>> keys(ticketMap)

'2R175'    '417R93'    '947F4'    'A479GY'    'B7398'    'NZ1452'

>> values(ticketMap)

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对数目

>> keys(ticketMap)

'2R175'    '417R93'    '947F4'    'A479GY'    'B7398'    'NZ1452'

>> values(ticketMap)

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)

[1]    [5]    [6]    [8]    [9]

>> values(m3)

'A'    'B'    'Z'    'X'    'Y'

>> m4 = [m2; m1];                     % m4与m3的合并顺序不同

>> keys(m4)

[1]    [5]    [6]    [8]    [9]

>> values(m4)

'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)

'2R175'    '417R93'    '947F4'    'A479GY'    'B7398'

>> values(ticketMap)

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')

Sarah Latham

修改乘客的名字为Anna Latham,可以通过以下命令来实现:

>> ticketMap('A479GY') = 'Anna Latham';

可以输入以下命令来验证修改的结果:

>> ticketMap('A479GY')

'Anna Latham';

3.修改Keys

如果需要在保持值不变的情况下对键名进行修改,首先需要删除键名和对应的值,然后再添加一个有正确键名的新条目。

【例3-38】  Map中的键修改示例。

在上例的基础上,修改乘客James Enright的机票号码:

>> remove(ticketMap, '2R175');  %  删除原有的机票号码条目

>> ticketMap('2S185') = 'James Enright';  %  添加新的机票号码条目

>> k = keys(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对象

unidentified person

通过查看原始Map对象可以发现,通过对副本的修改,原始对象也发生了改变。

>> remove(ticketMap, 'AZ12345');    %  删除原始对象中的条目

>> keys(ticketMap)

'2S185'    '417R93'    '947F4'    'A479GY'    'B7398'

>> keys(copiedMap)

'2S185'    '417R93'    '947F4'    'A479GY'    'B7398'

>> clear copiedMap;             %  删除副本

>> keys(ticketMap)                      %  并没有删除原始Map对象

'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')

ticketNum: 'B7398'

destination: 'Granada'

reserved: '30-Apr-2008'

origin: 'JFK'

>> seatingMap('15B').ticketNum

结合上面例子中的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对乘客的账户信息进行寻访,可以使用如下命令: