ruby way之hashes

本文详细介绍了Ruby中Hash的各种操作方法,包括创建、存取、删除、迭代等,并提供了丰富的示例代码。
1创建一个hash

就想创建一个数组一样,我们能够使用Hash的[]方法来创建一个hash:

[code]puts a1 = Hash.[]("flat",3,"curved",2)
puts a2 = Hash.[]("flat"=>3,"curved"=>2)
puts b1 = Hash["flat",3,"curved",2]
puts b2 = Hash["flat"=>3,"curved"=>2]
puts c2 = {"flat"=>3,"curved"=>2}[/code]

相似的,我们还可以使用new来创建一个hash:

[code]puts d = Hash.new # 创建一个空的hash
puts e = Hash.new(99) # 创建一个默认值为99的hash
puts f = Hash.new("a"=>3) #
puts e["angled"] # 99
puts e.inspect # {}
puts f["b"] # {"a"=>3} (刚好默认值也是一个hash)
puts f.inspect # {}[/code]

2指定一个默认值给hash

一个hash,如果你使用一个不存在的key去取值的话,将会返回给你一个nil,这里我们还可以自己定义默认值,从而来代替nil,或者我们还可以使用default=方法来改变它的默认值:

[code]puts a = Hash.new("missing") # default value object is "missing"
puts a["hello"] # "missing"
puts a.default="nothing"
puts a["hello"] # "nothing"
puts a["good"] << "bye" # "nothingbye"
puts a.default # "nothingbye"[/code]

如果当一个key不存在时,你想抛出一个异常来代替返回默认值的话,你可以使用fetch方法,当你使用fetch 方法的时候如果key不存在,它则会抛出一个IndexError异常,它还有第二个参数,这个参数就是当你key不存在的时候所返回的值:

[code]a = {"flat"=>3,"curved"=>2,"angled"=>5}
a.fetch("pointed") # IndexError
puts a.fetch("curved","na") # 2
puts a.fetch("x","na") # "na"
puts a.fetch("flat") {|x| x.upcase} # 3
puts a.fetch("pointed") {|x| x.upcase} # "POINTED"[/code]

3存取或者加一个键值对

hash也有像数组一样的[]和[]=方法,还有一个store,它是[]=方法的别名:

[code]a = {}
a["flat"] = 3 # {"flat"=>3}
a.[]=("curved",2) # {"flat"=>3,"curved"=>2}
a.store("angled",5) # {"flat"=>3,"curved"=>2,"angled"=>5}

puts a[/code]

在这里要注意,nil对象也可以作为一个健或者值:

[code]b={}
b[2] # nil
b[3]=nil
b # {3=>nil}
b[2].nil? # true
b[3].nil? # true
b[nil]=5
b # {3=>nil,nil=>5}
b[nil] # 5
b[b[3]] # 5[/code]

4删除一个键值对

删除的话我们能够使用 clear, delete, delete_if, reject, reject!, 和shift 这些方法都能做到。

clear 将会把一个hash清空.
shift则将会删除掉最前面的一个键值对:

[code]a = {1=>2, 3=>4}
b = a.shift # [1,2] a现在是[3=>4][/code]

delete删除一个指定位置的键值对,如果不存在这个位置,则将会返回block里的字符串:

[code]a = {1=>1, 2=>4, 3=>9, 4=>16}
a.delete(3) # 9
# a is now {1=>1, 2=>4, 4=>16}
a.delete(5) # nil in this case
a.delete(6) { "not found" } # "not found"[/code]

5迭代一个hash

我们能够使用each方法来做这个,它还有each_key, each_pair和 each_value方法,其中each_pair是each方法的别名:

[code]{"a"=>3,"b"=>2}.each do |key, val|
print val, " from ", key, "; " # 3 from a; 2 from b;
end[/code]

each_key 和each_value的block只有一个参数:

[code]{"a"=>3,"b"=>2}.each_key do |key|
print "key = #{key};" # Prints: key = a; key = b;
end

{"a"=>3,"b"=>2}.each_value do |value|
print "val = #{value};" # Prints: val = 3; val = 2;
end
[/code]

6转置一个hash

也就是将一个hash的键和值交换:

[code]a = {"fred"=>"555-1122","jane"=>"555-7779"}
b = a.invert
b["555-7779"] # "jane"[/code]

注意这里有一个问题,那就是值有可能是重复的,这时如果你使用invert的话,它将会删除掉一个重复的键值对:

[code]a = {"fred"=>"555-7779","jane"=>"555-7779"}
b = a.invert
puts b["555-7779"] # "jane"[/code]

7检测一个健或者值是否属于一个hash

我们能够使用has_key?或者它的任意一个别名,include?, key?, 和member?来测试一个key是否属于一个hash:

[code]a = {"a"=>1,"b"=>2}
a.has_key? "c" # false
a.include? "a" # true
a.key? 2 # false
a.member? "b" # true[/code]

你还能使用empty? 方法来测试一个hash是否为空,length来得到一个hash的大小:

[code]a.empty? # false
a.length # 2[/code]

如果想测试值的话,就使用has_value?或者value?:

[code]a.has_value? 2 # true
a.value? 99 # false[/code]

8 将一个hash转换为一个数组

可以使用to_a来讲一个hash转换成一个数组:

[code]h = {"a"=>1,"b"=>2}
h.to_a # ["a",1,"b",2][/code]

如果只想把值或者健转换成数组,可以使用keys或者values :

[code]h.keys # ["a","b"]
h.values # [1,2]
[/code]

最终你还可以基于一个健序列,来将他们所对应的值转换换成数组:

[code]h = {1=>"one",2=>"two",3=>"three",4=>"four","cinco"=>"five"}
h.values_at(3,"cinco",4) # ["three","five","four"]
h.values_at(1,3) # ["one","three"][/code]

9 根据条件选择键值对

Hash类混入了Enumerable 模块,因此你能够使用detect (find), select, (find_all), grep, min, max, 和reject 这些方法.

detect (别名find)得到一个单独的键值对:

[code]names = {"fred"=>"jones","jane"=>"tucker",
"joe"=>"tucker","mary"=>"SMITH"}
# 得到一个tucker
names.detect {|k,v| v=="tucker" } # ["joe","tucker"]
# 得到一个大写的
names.find {|k,v| v==v.upcase } # ["mary", "SMITH"][/code]


select(别名finad_all)将会返回所有符合条件的键值对:

[code]names.select {|k,v| v=="tucker" }
# [["joe", "tucker"], ["jane", "tucker"]]
names.find_all {|k,v| k.count("r")>0}
# [["mary", "SMITH"], ["fred", "jones"]][/code]

10 排序一个hash

ruby排序的时候是将hash转换为一个数组,然后才进行排序的:

[code]names = {"Jack"=>"Ruby","Monty"=>"Python",
"Blaise"=>"Pascal", "Minnie"=>"Perl"}
list = names.sort
# list is now:
# [["Blaise","Pascal"], ["Jack","Ruby"],
# ["Minnie","Perl"], ["Monty","Python"]][/code]

11 合并两个散列

ruby能够使用merge(别名update)方法,来合并两个hash,如果他们中的健有相同的话,一个将会被删除:

[code]dict = {"base"=>"foundation", "pedestal"=>"base"}
added = {"base"=>"non-acid", "salt"=>"NaCl"}
new_dict = dict.merge(added)
# {"base"=>"non-acid", "pedestal"=>"base", "salt"=>"NaCl"}[/code]

merge还可以使用block来处理,两个健有冲突的hash的合并,我们下面的代码是假设我们有两个冲突的健的话,我们选择值较小的那个键值对:

[code]dict = {"base"=>"foundation", "pedestal"=>"base"}
added = {"base"=>"non-acid", "salt"=>"NaCl"}
new_dict = dict.merge(added) {|key,old,new| old < new ? old : new }
# {"salt"=>"NaCl", "pedestal"=>"base", "base"=>"foundation"}[/code]


12 由一个数组来创建hash

[code]array = [2, 3, 4, 5, 6, 7]
hash = Hash[*array]
# hash is now: {2=>3, 4=>5, 6=>7}[/code]

13计算hash键的差集和交集

由于hash的key能够被转换成一个数组,因此我们能够使用一些数组的方法:

[code]a = {"a"=>1,"b"=>2,"z"=>3}
b = {"x"=>99,"y"=>88,"z"=>77}
intersection = a.keys & b.keys
difference = a.keys - b.keys
c = a.dup.update(b)
inter = {}
intersection.each {|k| inter[k]=c[k] }
# inter is {"z"=>77}
diff={}
difference.each {|k| diff[k]=c[k] }
# diff is {"a"=>1, "b"=>2}[/code]

14使用hash作为一个Sparse Matrix

我们能够这样做:

[code]cube = Hash.new(0)
cube[[2000,2000,2000]] = 2
z = cube[[36,24,36]] # 0[/code]

15一个简单的可以包含重复健的hash

这个很简单的实现,看下代码就行了:

[code]class HashDup

def initialize(*all)
raise IndexError if all.size % 2 != 0
@store = {}
if all[0] # not nil
keyval = all.dup
while !keyval.empty?
key = keyval.shift
if @store.has_key?(key)
@store[key] += [keyval.shift]
else
@store[key] = [keyval.shift]
end
end
end
end

def store(k,v)
if @store.has_key?(k)
@store[k] += [v]
else
@store[k] = [v]
end
end

def [](key)
@store[key]
end

def []=(key,value)
self.store(key,value)
end

def to_s
@store.to_s
end

def to_a
@store.to_a
end

def inspect
@store.inspect
end

def keys
result=[]
@store.each do |k,v|
result += ([k]*v.size)
end
result
end

def values
@store.values.flatten
end

def each
@store.each {|k,v| v.each {|y| yield k,y}}
end

alias each_pair each

def each_key
self.keys.each {|k| yield k}
end

def each_value
self.values.each {|v| yield v}
end

def has_key? k
self.keys.include? k
end

def has_value? v
self.values.include? v
end

def length
self.values.size
end

alias size length

def delete k
val = @store[k]
@store.delete k
val
end

def delete k,v
@store[k] -= [v] if @store[k]
v
end

# Other methods omitted here...

end


# This won't work... dup key will ignore
# first occurrence.
h = {1=>1, 2=>4, 3=>9, 4=>16, 2=>0}

# This will work...
h = HashDup.new(1,1, 2,4, 3,9, 4,16, 2,0)

k = h.keys # [4, 1, 2, 2, 3]
v = h.values # [16, 1, 4, 0, 9]

n = h.size # 5

h.each {|k,v| puts "#{k} => #{v}"}
# Prints:
# 4 => 16
# 1 => 1
# 2 => 4
# 2 => 0
# 3 => 9[/code]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值