पाठ 5 / 25

Arrays, Hashes and Enumerable

Work with arrays and hashes using Enumerable methods.

Collections with a rich toolbox

Arrays are ordered and can hold any objects: [1, "two", :three]. Hashes map keys to values and preserve insertion order: { "Pune" => 2, "Delhi" => 1 }, with the symbol shorthand { city: "Pune", total: 1200 }, and Ruby 3.1's value omission { city:, total: } uses local variables of the same names. Missing keys return nil; fetch(:key) raises instead, and fetch(:key, default) or Hash.new(0) provide defaults. Both include the Enumerable module, giving dozens of methods: each, map, select/filter, reject, find, reduce/sum, count, group_by, partition, sort_by, min_by/max_by, tally, each_with_object, each_slice, zip, flat_map, any?, all? and none?. Methods ending in ! (such as sort!, map!, uniq!) modify the receiver in place; their non-bang versions return new objects. &:symbol is shorthand for a block that calls that method: names.map(&:upcase). Lazy enumerators (.lazy) handle large or infinite sequences efficiently.

Enumerable in action

Grouping, summing and tallying orders with no explicit loops.

orders = [
  { id: "o1", city: "Pune",  total: 1200, paid: true },
  { id: "o2", city: "Delhi", total: 300,  paid: false },
  { id: "o3", city: "Pune",  total: 800,  paid: true },
]

paid = orders.select { |o| o[:paid] }
revenue = paid.sum { |o| o[:total] }                       # 2000
by_city = orders.group_by { |o| o[:city] }                  # { "Pune" => [...], "Delhi" => [...] }
city_totals = by_city.transform_values { |list| list.sum { _1[:total] } }   # Pune 2000, Delhi 300
largest = orders.max_by { |o| o[:total] }[:id]              # "o1"
city_counts = orders.map { |o| o[:city] }.tally             # { "Pune" => 2, "Delhi" => 1 }
unpaid, settled = orders.partition { |o| !o[:paid] }

stock = Hash.new(0)
%w[pen ink pen].each { |sku| stock[sku] += 1 }             # { "pen" => 2, "ink" => 1 }

city = "Mumbai"
total = 950
new_order = { city:, total: }                               # value omission (Ruby 3.1+)
puts new_order.fetch(:city)
puts %w[pune delhi].map(&:capitalize).inspect               # ["Pune", "Delhi"]

Bang methods change the receiver

list.sort returns a new sorted array; list.sort! sorts list itself. Also note that some bang methods return nil when nothing changed (such as uniq!), so do not chain them.

त्वरित जाँच: What does `orders.map(&:id)` do?

  • Deletes ids
  • Calls the id method on each element and returns an array of the results
  • Sorts by id
  • It is a syntax error
Answer

Calls the id method on each element and returns an array of the results — &:symbol converts the method name into a block that calls it on each element.