Ruby操纵数据结构(三)

18 、对数组迭代

Array 类有个我们希望的标准的迭代器each 。但是,它还其它很有用的迭代器。
reverse_each 方法以逆序迭代。它先使用reverse 计算然后使用each ,但它更快。这儿是个例子:
words = %w(Son I am able she said)
str = ""
words.reverse_each {
|w| str += "#{ w}
"}
# str is now "said she able am I Son "

如果我们只想在索引上迭代,我们可以使用each_inex x.each_inex 相当于(0..(x.size-1)).each ( 也就是,在索引范围内迭代)
迭代器each_with_index( 混合了Comparable) 将元素与索引两者传递给块,像下面:
x = ["alpha", "beta", "gamma"]
x.each_with_index do |x,i|

puts "Element #{ i}
is #{ x} "
end
# Produces three lines of output
如何以随机次序在数组上迭代呢?下面例子使用了迭代器random_each( 它简单地调用randomize 方法)
class Array
# 假设我们已经定义了randomize

def random_each

temp = self.randomize # 将数组打乱。

temp.each { |x| yield x}

end
end
dwarves = %w(Sleepy Dopey Happy Sneezy Grumpy Bashful Doc)
list = ""
dwarves.random_each { |x| list += "#{ x}
"}
# list is now:
# "Bashful Dopey Sleepy Happy Grumpy Doc Sneezy "
# (Your mileage may vary.)
译注:在文档中是这样描述
1.
array.each {|item| block } → array
为每个元素调用块。
2.
array.reverse_each {|item| block }
倒序each
3.
array.each_index {|index| block } → array 对每个索引调用块,each 是元素。
4.
enum.each_with_index {|obj, i| block } → enum 用元素,索引调用块


19 、以插入界定符的形式生成字符串

我们常常想在数组的两个元素之间以"fence post" 风格插入界定符;也就是说,我们想在元素之间放置界定符,但第一个或最后一个元素没有。方法join 将作这件事,就和你的* 操作符一样:
been_there = ["Veni", "vidi", "vici."]
journal = been_there.join(", ")
# "Veni, vidi, vici."
# Default delimiter is space
letters = [" hi","Mu","Alpha"]
musicians = letters.join
# " hi Mu Alpha"
people = ["Bob","Carol","Ted","Alice"]movie = people * " and "
# movie is now "Bob and Carol and Ted and Alice"
注意,如果我们真的想以不同方式处理最后一个元素,比如插入一个单词,我们得手工完成,像这样:
list = %w[A B C D E F]
with_commas = list[0..-2]*", " + ", and " + list[-1]
# with_commas is now "A, B, C, D, E, and F"
译注:文档是这样描述的
array.join(sep=$,) → str
sep 字符串夹在各元素中间使数组转换为字符串,并返回该字符串。若sep nil 则使用空字符串。若参数sep 被省略,则使用变量$, 的值。$, 的默认值为nil


20 、逆转数组

要逆转数组的次序,使用reverse reverse! 方法:
inputs = ["red", "green", "blue"]
outputs = inputs.reverse
# ["green","blue","red"]
priorities = %w(eat sleep code)
priorities.reverse!
# ["code","sleep","eat"]
译注:文档是这样描述的
array.reverse → an_array
array.reverse! → array


21 、从数组移除重复元素

如果我们想从数组移除重复元素,uniq 方法( uniq! 方法) 会完成这个工作:
breakfast = %w[spam spam eggs ham eggs spam]
lunch = breakfast.uniq
# ["spam","eggs","ham"]
breakfast.uniq!
# breakfast has changed now


22 、交叉数组

假设你想让两个数组" 交叉" 它们的元素并放入新数组中。这有很多方式。这儿是其中一个:
a = [1, 2, 3, 4]
b = ["a", "b", "c", "d"]
c = []
a.each_with_index { |x,i| c << x << b }
# c is now [1, "a", 2, "b", 3, "c", 4, "d"]


23、计算数组的频率值

没有像用于字符串(计算每个数据条目的出现次数)那样用于数组的count方法。不过,我们可自己创建一个:
class Array

def count

k=Hash.new(0)

self.each{ |x| k[x]+=1 }

k

end
end
meal = %w[spam spam eggs ham eggs spam]
items = meal.count
# items is { "ham" => 1, "spam" => 3, "eggs" => 2}
spams = items["spam"]
# 3
注意,返回的是个哈希表。


24、将数组转换为哈希表

数组用索引关联数据。但是,若是我们想转换它呢(也就是,由索引关联的数据能产生哈希表吗)?下面方法会做到这些:
class Array

def invert

h={ }

self.each_with_index{ |x,i| h[x]=i}

h

end
end
a = ["red","yellow","orange"]
h = a.invert
# { "orange"=>2, "yellow"=>1, "red"=>0}


25Synchronized Sorting of Multiple Arrays
假设你想排序一个数组,但你的另一个数组与它有元素对元素的对应关系。换句话说,你不能在同步之外获取它们。哪你应该怎样做呢?

我们在Listing3.7中的解答将排序一个数组和收集做为结果的索引。索引列表(本身是数组)可以应用到任何其它数组来以同样的次序放置它元素。

Listing 3.7 Synchronized Array Sorting
class Array

def sort_index

d=[]

self.each_with_index{ |x,i| d=[x,i]}

if block_given?

d.sort { |x,y| yield x[0],y[0]} .collect{ |x| x[1]}

else

d.sort.collect{ |x| x[1]}

end

end

def sort_by(ord=[])

return nil if self.length!=ord.length

self.indexes(*ord)

end
end
a = [21, 33, 11, 34, 36, 24, 14]
p a
p b=a.sort_index
p a.sort_by b
p c=a.sort_index { |x,y| x%2 <=> y%2}
p a.sort_by c


26、为数组新元素指定缺省值

当一个数组增长时它会创建未定义的新元素,这些元素的缺省值是nil值:
a = Array.new
a[0]="x"
a[3]="y"
# a is now ["x", nil, nil, "y"]
如果我们想用一些其它值设置这些新元素,该怎么做呢?做为个通用原则,我们在Listing3.8中提供了ZArray类,它将未定义新元素设置为0
Listing 3.8 Specifying a Default for Array Elements
class ZArray < Array

def [](x)

if x > size

for i in size+1..x

self=0

end

end

v = super(x)

end

def []=(x,v)

max = size

super(x,v)

if size - max > 1

(max..size-2).each do |i|

self = 0

end

end

end
end
num = ZArray.new
num[1] = 1
num[2] = 4
num[5] = 25
# num is now [0, 1, 4, 0, 0, 25]
[url=http://my4java.itpub.net/post/9983/@MSITStore:Cocuments %20and%20SettingsAdministrator桌面the%20ruby%20way.chm::/comete/?x=1& mode=section&sortKey=rank&sortOrder=desc&view=book&xmlid=0-672-32083-5/30041534&g=&catid=&s=1&b=1&f=1&t=1&c=1&u=1&r=&o=1&n=1&d=1&p=1&a=0][/url]


二、用哈希表工作

哈希表被称为关联数组,字典等其它名称。事实上,PerlJava程序员会很熟悉这个数组结构。
想想数组做为一个实体,它将索引x与数据条目y关联到一起。哈希表也创建了类似的关联,但至少有两个例外。首先,对于数组,x总是个整数;对于哈希表,它不需要这样。其次,数组是有序数据结构;典型的哈希表是无序的。
哈希表的键可以是任何类型。带来的副作用是,它使用哈希表成了非有序数据结构。在数组内,我们知道元素4跟随在元素3的后面;但在哈希表中,键可能是这样个类型,它没有定义的前任或后续。基于这个原因(也有其它的)Ruby不关注哈希表的任何特定次序。
你可以认为哈希表就像是带有特定的索引的数组,或者是数据库中带有两个字段的同义表。不论你怎样认为哈希表,它都有强大的有用的程序结构。


1、创建哈希表

就像数组,特定类方法[ ]被用于创建哈希表。方括号内的数据条目列表被用于哈希表内的映射。
下面显示了这个方法的六种不同的调用:
a1 = Hash.[]("flat",3,"curved",2)
a2 = Hash.[]("flat"=>3,"curved"=>2)
b1 = Hash["flat",3,"curved",2]
b2 = Hash["flat"=>3,"curved"=>2]
c1 = { "flat",3,"curved",2}
c2 = { "flat"=>3,"curved"=>2}
# 对于 a1, b1, c1: 元素数量必须是偶数
同样,类方法new可以接受一个指定缺省值的参数。注意这个缺省值不是哈希表的真正组成部分;它只是用返回值来替换nil。这儿是例子:
d = Hash.new
# 创建空哈希表
e = Hash.new(99)
#创建空哈希表
f = Hash.new("a"=>3) #创建空哈希表
e["angled"]
# 99
e.inspect
# { }
f["b"]
# { "a"=>3}
(default value is actually a hash itself)
f.inspect
# { }
译注:文档是这样描述的
1.
Hash[ [key =>|, value]* ] => hash
2.
Hash.new => hash
3.
Hash.new(obj) => aHash
4.
Hash.new {|hash, key| block } => aHash
使用第一种形式时,参数的个数必须是偶数。(奇数位参数是索引,偶数位参数是元素值)。也可以将一个哈希表对象指定给参数时,将生成并返回一个与指定哈希表相同的全新的哈希表。(生成的哈希表的默认值为nil)
以下是从数组生成哈希表的方法示例(可能您觉得应该有更直接的方法,但实际上并没有)

1 [索引, , ...] 型的数组变为哈希表
ary = [1,"a", 2,"b", 3,"c"]
p Hash[*ary]
# => {1=>"a", 2=>"b", 3=>"c"}
2 由索引和值配对出现的数组变为哈希表
alist = [[1,"a"], [2,"b"], [3,"c"]]
p Hash[*alist.flatten]
#=> {1=>"a", 2=>"b", 3=>"c"}
3 由索引数组和值数组配对生成哈希表(version 1.7 以后)
keys = [1, 2, 3]
vals = ["a", "b", "c"]
alist = keys.zip(vals)
# alist = [keys,vals].transpose
p Hash[*alist.flatten]
#=> {1=>"a", 2=>"b", 3=>"c"}
4 虽然索引和值都是数组,但还是无法使用(2)(3)的方法时,只好老老实实地赋值了
h = Hash.new
alist = [[1,["a"]], [2,["b"]], [3,["c"]]]
alist.each {|k,v|

h[k] = v
}
p h
#=> {1=>["a"], 2=>["b"], 3=>["c"]}
new 生成一个全新的空哈希表.若索引没有对应值时,其默认值为ifnone.您必须谨慎地处理默认值的问题(trap::Hash).
ruby 1.7 特性:若指定了块时,则块的计算值将成为默认值.每当调用无值的哈希表元素时,都会对块进行计算,然后返回其结果.而调用哈希表时的索引将被传递给该块.
# 若没有使用块时, 一旦改变默认值将会影响到其他的值
h = Hash.new("foo")
p h[1]

# => "foo"
p h[1] << "bar"
# => "foobar"
p h[1]
# => "foobar"
p h[2]
# => "foobar"
# 若使用块的话,问题便会迎刃而解
h = Hash.new {|hash, key| hash[key] = "foo"}
p h[1]
# => "foo"
p h[1] &

 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值