Windows PowerShell每周提示(15):与哈希表共事
在上周的Windows PowerShell提示中我们向你介绍了.NET Framework类System.Collections.ArrayList,把这个类定位为作为内建于Windows PowerShell中的数组的替代。(为什么你需要内建在Windows PowerShell中的数组类的替代?好的,有一件事,ArrayList能简单的从数组删除项目,这件事对内置的数组而言几乎是不可能的)在同样的专栏中我们承诺,本周,我们将会讨论对Windows PowerShell中使用数组而言的另外一个可选的方案:哈希表。好的,不要一直说脚本专家们不一直遵守他们的诺言。
|
注意:好的,技术上我们不总是遵守我们的承诺。我们只是不想被那样说罢了。 |
尽管哈希表这个术语对你们中的很多人来说是新名词,那么现在就是你熟悉这方面概念的好机会了;毕竟,哈希表是简单的名称-值的集合,同FileSystemObejct的Dictionary对象很相似。例如,假设你有一组美国州名及其首府的集合。每一个州只有一个,也仅有一个,首府(例如,华盛顿的州首府是奥林匹亚),给出的城市只能是一个州的首府。如果你想要记录并使用这个信息,你能构造一个二维数组。或者你能采取更简单的方法,创建哈希表。
谈论的够多了,让我们看看一些代码。假设你真的想要一个包含美国州及它们首府的列表的一个哈希表;你打算怎么样创建呢?好的,这里有一个方法:
|
$states = @{"Washington" = "Olympia"; "Oregon" = "Salem"; California = "Sacramento"} |
姑且承认第一眼看上去有点难以理解;然而幸运的是,这不像看上去的那样复杂。我们在这所做的是将三对键-值对赋值给名为$states的哈希表。如你所见,创建哈希表的语法包括一个@标记后跟一对花括号。
|
注意: @只在英文中被称为at标记;在其它语言中,它有一些很酷的称法,像maggot, monkey’s tail, and pickled herrin。 |
那么在花括号内发生了什么呢?好的,这是我们指定键-值对的地方,使用这样的语法key = value;例如:"Washington" = "Olympia"。注意我们使用分号分隔每一对独立的键-值;所以使用语法就是"Washington" = "Olympia"; "Oregon" = "Salem"。
那么当我们运行我们的哈希表命令之后$states变量会等于什么呢?为什么这么问,当然,是以下内容:
|
ame Value
---- -----
California Sacramento
Washington Olympia
Oregon Salem |
这很好 ,除了一件事:我们的哈希表离完整还很远。(毕竟,我们只列出来三个州,而事实上……呃……美国不止三个州)那么你如何向已存在的哈希表内添加新的键-值对呢?好的,我们不知道你怎么样,但是下面是脚本专家如何实现的:
|
$states.Add("Alaska", "Fairbanks") |
|
注意: 是的,是的,我们知道:费尔班克斯不是阿拉斯加的首府。我们等会会说明的。 |
不用多说,没有比这更有想象力的事了:我们简单的调用Add方法,并转递给这个方法两个参数:新键("Alaska")及新值("Fairbanks")。现在我们看下$states的值:
|
Name Value
---- -----
California Sacramento
Alaska Fairbanks
Washington Olympia
Oregon Salem |
顺便说一句,这是一个好的观察点:我们永远不知道新条目将会确切的出现在哈希表的哪个位置。在这种情况下,例如,我们的新条目不晓得什么缘故成为有4个项目表中的第二个。但是这没什么;在我们走之前我们会向你展示怎么样测试已存在的键或值而不用顾及他们在哈希表中的位置。然后,因为遇到这种糟糕的事,我们也将会向你展示如何对表进行排序。
不过要紧的是,潮水般的电子邮件和电话使得事情变得很清楚,阿拉斯加的州首府所在地毕竟不是费尔班克斯,而是朱诺。然而不幸的是,我们已经向我们的哈希表添加了这个错误的键-值。现在我们打算怎么办?
好的,一件我们能做的事情是简单的移除得罪人的项目。想要删除Alaska键-值对?好的,除了Remove方法外你还能用什么?
为了安全起见,我们再看下$states的值:
|
Name Value
---- -----
California Sacramento
Washington Olympia
Oregon Salem |
好多了,不是么?
另外,我们也能使用Set_Item方法来改变赋值给Alaska的值:
|
$states.Set_Item("Alaska", "Juneau") |
运行这这个命令,然后看下$states的值,应当和以下的输出相同:
|
Name Value
---- -----
California Sacramento
Alaska Juneau
Washington Olympia
Oregon Salem |
顺便说一句,既然有Set_Item方法那么自然有名为Get_Item的方法。这方法使得我们能够提取和哈希表中指定项目相关的值。不确定俄勒冈的首府是哪座城市?那么运行以下命令,你自己来寻找答案吧:
|
$states.Get_Item("Oregon") |
现在假设,俄勒冈州没有出现在你的哈希表内,那么当你运行先前命令的时候会发生什么?好的,实际上,不会发生什么:你不会得到任何类型的返回值,也不会得到错误消息。这确实是一个问题:在看上去什么都发生的情况下去找出到底发生了什么是需要一点技巧的。
幸运的是,你能够使用ContainsKey及ContainsValue方法来寻找哈希表内的项目。想要知道一个名为Oregon的项目是否存在于你的哈希表内?那么就调用ContainsKey方法吧,像这样:
|
$states.ContainsKey("Oregon") |
这个方法返回True如果在哈希表内找到名为Oregon的项,如果没有找到则返回False。同样的,你能通过使用ContainsValue方法寻找在哈希表内是否包含指定的值:
|
$states.ContainsValue("Salem") |
|
注意: 如果仅想知道在哈希表内有多少个像的话,你能简单回显Count属性的值:$states.Count |
最后,但是却是重要的,让我们讨论对哈希表进行排序。这需要点小技巧,下面的命令将不会工作:
为什么不能工作呢?好的,在先前的命令中哈希表是作为单独的对象被发送的,因此对Sort-Object cmdlet而言就没什么东西能排序了。如果我们想要对哈希表进行排序我们需要使用GetEnumerator方法,这将有效的穿过管道符发送哈希表内的每一个条目,使每个条目作为独立的对象:
|
$states.GetEnumerator() | Sort-Object Name |
因此我们将得到以下类似的输出:
|
Name Value
---- -----
Alaska Juneau
California Sacramento
Oregon Salem
Washington Olympia |
这里有一个相似的命令,除了这个是用来对哈希表的值进行降序排序的(仅仅因为我们想要秀一下):
|
$states.GetEnumerator() | Sort-Object Value -descending |
下面是该命令得到的输出:
|
Name Value
---- -----
Oregon Salem
California Sacramento
Washington Olympia
Alaska Juneau |
很酷,不是么?
英文原文
http://www.microsoft.com/technet/scriptcenter/resources/pstips/sept07/pstip0914.mspx