age = { "Nat", 24,
"Jules", 25,
"Josh", 17 }
age["Nat"] = 24
age["Jules"] = 25
age["Josh"] = 17
food_color = {
"Apple" => "red",
"Banana" => "yellow",
"Lemon" => "yellow",
"Carrot" => "orange"
}
# In Ruby, you cannot avoid the double or simple quoting
# while manipulatin hashes
|
hash[key] = value food_color["Raspberry"] = "pink" puts "Known foods:", food_color.keys |
# does hash have a value for key ? if (hash.has_key?(key)) # it exists else # it doesn't end [ "Banana", "Martini" ].each { |name| print name, " is a ", food_color.has_key?(name) ? "food" : "drink", "\n" } age = {} age['Toddler'] = 3 age['Unborn'] = 0 age['Phantasm'] = nil for thing in ['Toddler', 'Unborn', 'Phantasm', 'Relic'] print "#{thing}: " print "Has-key " if age.has_key?(thing) print "True " if age[thing] print "Nonzero " if age[thing] && age[thing].nonzero? print "\n" end #=> # Toddler: Has-key True Nonzero # Unborn: Has-key True # Phantasm: Has-key # Relic: # You use Hash#has_key? when you use Perl's exists -> it checks # for existence of a key in a hash. # All Numeric are "True" in ruby, so the test doesn't have the # same semantics as in Perl; you would use Numeric#nonzero? to # achieve the same semantics (false if 0, true otherwise). |
food_color.delete("Banana") |
hash.each { |key, value|
# do something with key and value
}
hash.each_key { |key|
# do something with key
}
food_color.each { |food, color|
puts "#{food} is #{color}"
}
food_color.each_key { |food|
puts "#{food} is #{food_color[food]}"
}
# IMO this demonstrates that OO style is by far more readable
food_color.keys.sort.each { |food|
puts "#{food} is #{food_color[food]}."
}
#-----------------------------
#!/usr/bin/ruby
# countfrom - count number of messages from each sender
# Default value is 0
from = Hash.new(0)
while gets
/^From: (.*)/ and from[$1] += 1
end
# More useful to sort by number of received mail by person
from.sort {|a,b| b[1]<=>a[1]}.each { |v|
puts "#{v[1]}: #{v[0]}"
}
#-----------------------------
|
# You may use the built-in 'inspect' method this way: p hash # Or do it the Cookbook way: hash.each { |k,v| puts "#{k} => #{v}" } # Sorted by keys hash.sort.each { |e| puts "#{e[0]} => #{e[1]}" } # Sorted by values hash.sort{|a,b| a[1]<=>b[1]}.each { |e| puts "#{e[0]} => #{e[1]}" } |
# Use the OrderedHash module (part of the GoodLibs RubyGem): require 'rubygems' require 'ordered_hash' hash = OrderedHash.new; # manipulate hash keys = hash.keys # keys is in insertion order # initialize require 'rubygems' require 'ordered_hash' food_color = OrderedHash.new food_color["Banana"] = "Yellow" food_color["Apple"] = "Green" food_color["Lemon"] = "Yellow" puts "In insertion order, the foods are:" food_color.each_key { |food| puts " #{food}" } puts "Still in insertion order, the foods' colors are:" food_color.each { |food, color| puts "#{food} is colored #{color}." } |
ttys = Hash.new for i in `who` user, tty = i.split (ttys[user] ||= []) << tty # see problems_ruby for more infos end ttys.keys.sort.each { |k| puts "#{k}: #{commify_series(ttys[k])}" # from 4.2 } |
surname = { "Mickey" => "Mantle", "Babe" => "Ruth" }
puts surname.index("Mantle")
# If you really needed to 'invert' the whole hash, use Hash#invert
#-----------------------------
#!/usr/bin/ruby -w
# foodfind - find match for food or color
given = ARGV.shift or raise "usage: foodfind food_or_color"
color = {
"Apple" => "red",
"Banana" => "yellow",
"Lemon" => "yellow",
"Carrot" => "orange",
}
if (color.has_key?(given))
puts "#{given} is a food with color #{color[given]}."
end
if (color.has_value?(given))
puts "#{color.index(given)} is a food with color #{given}."
end
#-----------------------------
|
# Sorted by keys (Hash#sort gives an Array of pairs made of each key,value) food_color.sort.each { |f| puts "#{f[0]} is #{f[1]}." } # Sorted by values food_color.sort { |a,b| a[1] <=> b[1] }.each { |f| puts "#{f[0]} is #{f[1]}." } # Sorted by length of values food_color.sort { |a,b| a[1].length <=> b[1].length }.each { |f| puts "#{f[0]} is #{f[1]}." } |
merged = a.clone.update(b) # because Hash#update changes object in place drink_color = { "Galliano" => "yellow", "Mai Tai" => "blue" } ingested_color = drink_color.clone.update(food_color) substance_color = {} for i in [ food_color, drink_color ] i.each_key { |k| if substance_color.has_key?(k) puts "Warning: #{k} seen twice. Using the first definition." next end substance_color[k] = 1 } end |
common = hash1.keys & hash2.keys this_not_that = hash1.keys - hash2.keys |
# no problem here, Ruby handles any kind of object for key-ing # (it takes Object#hash, which defaults to Object#id) |
# AFAIK, not possible in Ruby |
# Be careful, the following is possible only because Fixnum objects are # special (documentation says: there is effectively only one Fixnum object # instance for any given integer value). count = Hash.new(0) array.each { |e| count[e] += 1 } |
father = {
"Cain" , "Adam",
"Abel" , "Adam",
"Seth" , "Adam",
"Enoch" , "Cain",
"Irad" , "Enoch",
"Mehujael" , "Irad",
"Methusael" , "Mehujael",
"Lamech" , "Methusael",
"Jabal" , "Lamech",
"Jubal" , "Lamech",
"Tubalcain" , "Lamech",
"Enos" , "Seth",
}
while gets
chomp
begin
print $_, " "
end while $_ = father[$_]
puts
end
children = {}
father.each { |k,v|
(children[v] ||= []) << k
}
while gets
chomp
puts "#{$_} begat #{(children[$_] || ['Nobody']).join(', ')}.\n"
end
includes = {}
files.each { |f|
begin
for l in IO.readlines(f)
next unless l =~ /^\s*#\s*include\s*<([^>]+)>/
(includes[$1] ||= []) << f
end
rescue SystemCallError
$stderr.puts "#$! (skipping)"
end
}
include_free = includes.values.flatten.uniq - includes.keys |
# dutree - print sorted intented rendition of du output #% dutree #% dutree /usr #% dutree -a #% dutree -a /bin # The DuNode class collects all information about a directory, # and provides some convenience methods class DuNode attr_reader :name attr_accessor :size attr_accessor :kids def initialize(name) @name = name @kids = [] @size = 0 end # support for sorting nodes with side def size_compare(node2) @size <=> node2.size end def basename @name.sub(/.*\//, "") end #returns substring before last "/", nil if not there def parent p = @name.sub(/\/[^\/]+$/,"") if p == @name nil else p end end end # The DuTree does the acdtual work of # getting the input, parsing it, builging up a tree # and format it for output class Dutree attr_reader :topdir def initialize @nodes = Hash.new @dirsizes = Hash.new(0) @kids = Hash.new([]) end # get a node by name, create it if it does not exist yet def get_create_node(name) if @nodes.has_key?(name) @nodes[name] else node = DuNode.new(name) @nodes[name] = node node end end # run du, read in input, save sizes and kids # stores last directory read in instance variable topdir def input(arguments) name = "" cmd = "du " + arguments.join(" ") IO.popen(cmd) { |pipe| pipe.each { |line| size, name = line.chomp.split(/\s+/, 2) node = get_create_node(name) node.size = size.to_i @nodes[name] = node parent = node.parent if parent get_create_node(parent).kids.push(node) end } } @topdir = @nodes[name] end # figure out how much is taken in each directory # that isn't stored in the subdirectories. Add a new # fake kid called "." containing that much. def get_dots(node) cursize = node.size for kid in node.kids cursize -= kid.size get_dots(kid) end if node.size != cursize newnode = get_create_node(node.name + "/.") newnode.size = cursize node.kids.push(newnode) end end # recursively output everything # passing padding and number width as well # on recursive calls def output(node, prefix="", width=0) line = sprintf("%#{width}d %s", node.size, node.basename) puts(prefix + line) prefix += line.sub(/\d /, "| ") prefix.gsub!(/[^|]/, " ") if node.kids.length > 0 # not a bachelor node kids = node.kids kids.sort! { |a,b| b.size_compare(a) } width = kids[0].size.to_s.length for kid in kids output(kid, prefix, width) end end end end tree = Dutree.new tree.input(ARGV) tree.get_dots(tree.topdir) tree.output(tree.topdir) |