single_level = [ "this", "that", "the", "other" ] # Ruby directly supports nested arrays double_level = [ "this", "that", [ "the", "other" ] ] still_single_level = [ "this", "that", [ "the", "other" ] ].flatten |
a = [ "quick", "brown", "fox" ] a = %w(Why are you teasing me?) lines = <<"END_OF_HERE_DOC".gsub(/^\s*(.+)/, '\1') The boy stood on the burning deck, It was as hot as glass. END_OF_HERE_DOC bigarray = IO.readlines("mydatafile").collect { |l| l.chomp } name = "Gandalf" banner = %Q(Speak, #{name}, and welcome!) host_info = `host #{his_host}` %x(ps #{$$}) banner = 'Costs only $4.95'.split(' ') rax = %w! ( ) < > { } [ ] ! |
def commify_series(arr) return '' if not arr case arr.size when 0 then '' when 1 then arr[0] when 2 then arr.join(' and ') else arr[0..-2].join(', ') + ', and ' + arr[-1] end end array = [ "red", "yellow", "green" ] print "I have ", array, " marbles\n" # -> I have redyellowgreen marbles # But unlike Perl: print "I have #{array} marbles\n" # -> I have redyellowgreen marbles # So, needs: print "I have #{array.join(' ')} marbles\n" # -> I have red yellow green marbles #!/usr/bin/ruby # communify_series - show proper comma insertion in list output def commify_series(arr) return '' if not arr sepchar = arr.find { |p| p =~ /,/ } ? '; ' : ', ' case arr.size when 0 then '' when 1 then arr[0] when 2 then arr.join(' and ') else arr[0..-2].join(sepchar) + sepchar + 'and ' + arr[-1] end end lists = [ [ 'just one thing' ], %w(Mutt Jeff), %w(Peter Paul Mary), [ 'To our parents', 'Mother Theresa', 'God' ], [ 'pastrami', 'ham and cheese', 'peanut butter and jelly', 'tuna' ], [ 'recycle tired, old phrases', 'ponder big, happy thoughts' ], [ 'recycle tired, old phrases', 'ponder big, happy thoughts', 'sleep and dream peacefully' ], ] for list in lists do puts "The list is: #{commify_series(list)}." end |
# (note: AFAIK Ruby doesn't allow gory change of Array length) # grow the array by assigning nil to past the end of array ary[new_size-1] = nil # shrink the array by slicing it down ary.slice!(new_size..-1) # init the array with given size Array.new(number_of_elems) # assign to an element past the original end enlarges the array ary[index_new_last_elem] = value def what_about_that_array(a) print "The array now has ", a.size, " elements.\n" # Index of last element is not really interesting in Ruby print "Element #3 is `#{a[3]}'.\n" end people = %w(Crosby Stills Nash Young) what_about_that_array(people) |
# OO style bad_users.each { |user| complain(user) } # or, functional style for user in bad_users complain(user) end for var in ENV.keys.sort puts "#{var}=#{ENV[var]}" end for user in all_users disk_space = get_usage(user) if (disk_space > MAX_QUOTA) complain(user) end end for l in IO.popen("who").readlines print l if l =~ /^gc/ end # we can mimic the obfuscated Perl way while fh.gets # $_ is set to the line just read chomp # $_ has a trailing \n removed, if it had one split.each { |w| # $_ is split on whitespace # but $_ is not set to each chunk as in Perl print w.reverse } end # ...or use a cleaner way for l in fh.readlines l.chomp.split.each { |w| print w.reverse } end # same drawback as in problem 1.4, we can't mutate a Numeric... array.collect! { |v| v - 1 } a = [ .5, 3 ]; b = [ 0, 1 ] for ary in [ a, b ] ary.collect! { |v| v * 7 } end puts "#{a.join(' ')} #{b.join(' ')}" # we can mutate Strings, cool; we need a trick for the scalar for ary in [ [ scalar ], array, hash.values ] ary.each { |v| v.strip! } # String#strip rules :) end |
# not relevant in Ruby since we have always references for item in array # do somethingh with item end |
unique = list.uniq # generate a list of users logged in, removing duplicates users = `who`.collect { |l| l =~ /(\w+)/; $1 }.sort.uniq puts("users logged in: #{commify_series(users)}") # see 4.2 for commify_series |
a - b # [ 1, 1, 2, 2, 3, 3, 3, 4, 5 ] - [ 1, 2, 4 ] -> [3, 5] |
union = a | b intersection = a & b difference = a - b |
array1.concat(array2) # if you will assign to another object, better use: new_ary = array1 + array2 members = [ "Time", "Flies" ] initiates = [ "An", "Arrow" ] members += initiates members = [ "Time", "Flies" ] initiates = [ "An", "Arrow" ] members[2,0] = [ "Like", initiates ].flatten members[0] = "Fruit" members[3,2] = "A", "Banana" |
reversed = ary.reverse ary.reverse_each { |e| # do something with e } descending = ary.sort.reverse descending = ary.sort { |a,b| b <=> a } |
# remove n elements from front of ary (shift n) front = ary.slice!(0, n) # remove n elements from the end of ary (pop n) end_ = ary.slice!(-n .. -1) # let's extend the Array class, to make that useful class Array def shift2() slice!(0 .. 1) # more symetric with pop2... end def pop2() slice!(-2 .. -1) end end friends = %w(Peter Paul Mary Jim Tim) this, that = friends.shift2 beverages = %w(Dew Jolt Cola Sprite Fresca) pair = beverages.pop2 |
# use Enumerable#detect (or the synonym Enumerable#find) highest_eng = employees.detect { |emp| emp.category == 'engineer' } |
# use Enumerable#select (or the synonym Enumerable#find_all) bigs = nums.select { |i| i > 1_000_000 } pigs = users.keys.select { |k| users[k] > 1e7 } matching = `who`.select { |u| u =~ /^gnat / } engineers = employees.select { |e| e.position == 'Engineer' } secondary_assistance = applicants.select { |a| a.income >= 26_000 && a.income < 30_000 } |
# normally you would have an array of Numeric (Float or # Fixnum or Bignum), so you would use: sorted = unsorted.sort # if you have strings representing Integers or Floats # you may specify another sort method: sorted = unsorted.sort { |a,b| a.to_f <=> b.to_f } # let's use the list of my own PID's `ps ux`.split("\n")[1..-1]. select { |i| i =~ /^#{ENV['USER']}/ }. collect { |i| i.split[1] }. sort { |a,b| a.to_i <=> b.to_i }.each { |i| puts i } puts "Select a process ID to kill:" pid = gets.chomp raise "Exiting ... \n" unless pid && pid =~ /^\d+$/ Process.kill('TERM', pid.to_i) sleep 2 Process.kill('KILL', pid.to_i) descending = unsorted.sort { |a,b| b.to_f <=> a.to_f } |
ordered = unordered.sort { |a,b| compare(a,b) } precomputed = unordered.collect { |e| [compute, e] } ordered_precomputed = precomputed.sort { |a,b| a[0] <=> b[0] } ordered = ordered_precomputed.collect { |e| e[1] } ordered = unordered.collect { |e| [compute, e] }. sort { |a,b| a[0] <=> b[0] }. collect { |e| e[1] } for employee in employees.sort { |a,b| a.name <=> b.name } print employee.name, " earns \$ ", employee.salary, "\n" end # Beware! `0' is true in Ruby. # For chaining comparisons, you may use Numeric#nonzero?, which # returns num if num is not zero, nil otherwise sorted = employees.sort { |a,b| (a.name <=> b.name).nonzero? || b.age <=> a.age } users = [] # getpwent is not wrapped in Ruby... let's fallback IO.readlines('/etc/passwd').each { |u| users << u.split(':') } users.sort! { |a,b| a[0] <=> b[0] } for user in users puts user[0] end sorted = names.sort { |a,b| a[1, 1] <=> b[1, 1] } sorted = strings.sort { |a,b| a.length <=> b.length } # let's show only the compact version ordered = strings.collect { |e| [e.length, e] }. sort { |a,b| a[0] <=> b[0] }. collect { |e| e[1] } ordered = strings.collect { |e| [/\d+/.match(e)[0].to_i, e] }. sort { |a,b| a[0] <=> b[0] }. collect { |e| e[1] } print `cat /etc/passwd`.collect { |e| [e, e.split(':').indexes(3,2,0)].flatten }. sort { |a,b| (a[1] <=> b[1]).nonzero? || (a[2] <=> b[2]).nonzero? || a[3] <=> b[3] }. collect { |e| e[0] } |
circular.unshift(circular.pop) # the last shall be first circular.push(circular.shift) # and vice versa def grab_and_rotate(l) l.push(ret = l.shift) ret end processes = [1, 2, 3, 4, 5] while (1) process = grab_and_rotate(processes) puts "Handling process #{process}" sleep 1 end |
def fisher_yates_shuffle(a) (a.size-1).downto(1) { |i| j = rand(i+1) a[i], a[j] = a[j], a[i] if i != j } end def naive_shuffle(a) for i in 0...a.size j = rand(a.size) a[i], a[j] = a[j], a[i] end end |
#!/usr/bin/env ruby # example 4-2 words # words - gather lines, present in colums # class to encapsulate the word formatting from the input class WordFormatter def initialize(cols) @cols = cols end # helper to return the length of the longest word in the wordlist def maxlen(wordlist) max = 1 for word in wordlist if word.length > max max = word.length end end max end # process the wordlist and print it formmated into columns def output(wordlist) collen = maxlen(wordlist) + 1 columns = @cols / collen columns = 1 if columns == 0 rows = (wordlist.length + columns - 1) / columns # now process each item, picking out proper piece for this position 0.upto(rows * columns - 1) { |item| target = (item % columns) * rows + (item / columns) eol = ((item+1) % columns == 0) piece = wordlist[target] || "" piece = piece.ljust(collen) unless eol print piece puts if eol } # no need to finish it up, because eol is always true for the last element end end # get nr of chars that fit in window or console, see PLEAC 15.4 # not portable -- linux only (?) def getWinCharWidth() buf = "\0" * 8 $stdout.ioctl(0x5413, buf) ws_row, ws_col, ws_xpixel, ws_ypixel = buf.unpack("$4") ws_col || 80 rescue 80 end # main program cols = getWinCharWidth() formatter = WordFormatter.new(cols) words = readlines() words.collect! { |line| line.chomp } formatter.output(words) |
# In ruby, Fixnum's are automatically converted to Bignum's when # needed, so there is no need for an extra module def factorial(n) s = 1 while n > 0 s *= n n -= 1 end s end puts factorial(500) #--------------------------------------------------------- # Example 4-3. tsc-permute # tsc_permute: permute each word of input def permute(items, perms) unless items.length > 0 puts perms.join(" ") else for i in items newitems = items.dup newperms = perms.dup newperms.unshift(newitems.delete(i)) permute(newitems, newperms) end end end # In ruby the main program must be after all definitions it is using permute(ARGV, []) #--------------------------------------------------------- # mjd_permute: permute each word of input def factorial(n) s = 1 while n > 0 s *= n n -= 1 end s end # we use a class with a class variable store the private cache # for the results of the factorial function. class Factorial @@fact = [ 1 ] def Factorial.compute(n) if @@fact[n] @@fact[n] else @@fact[n] = n * Factorial.compute(n - 1) end end end #--------------------------------------------------------- # Example 4-4- mjd-permute # n2pat(n, len): produce the N-th pattern of length len # We must use a lower case letter as parameter N, otherwise it is # handled as constant Length is the length of the resulting # array, not the index of the last element (length -1) like in # the perl example. def n2pat(n, length) pat = [] i = 1 while i <= length pat.push(n % i) n /= i i += 1 end pat end # pat2perm(pat): turn pattern returned by n2pat() into # permutation of integers. def pat2perm(pat) source = (0 .. pat.length - 1).to_a perm = [] perm.push(source.slice!(pat.pop)) while pat.length > 0 perm end def n2perm(n, len) pat2perm(n2pat(n,len)) end # In ruby the main program must be after all definitions while gets data = split # the perl solution has used $#data, which is length-1 num_permutations = Factorial.compute(data.length()) 0.upto(num_permutations - 1) do |i| # in ruby we can not use an array as selector for an array # but by exchanging the two arrays, we can use the collect method # which returns an array with the result of all block invocations permutation = n2perm(i, data.length).collect { |j| data[j] } puts permutation.join(" ") end end |