rubyguides

Array#rassoc

array.rassoc(obj) -> sub_array or nil

The rassoc method searches a list of pairs for the first entry whose second element equals the given value. It is the mirror image of Array#assoc: where assoc matches on the first element of each pair, rassoc matches on the second. Both methods return the whole matched entry, not just the second element, so the caller can read whichever column it needs after the lookup.

Basic Usage

table = [["a", 1], ["b", 2], ["c", 3]]

table.rassoc(2)   # => ["b", 2]
table.rassoc(99)  # => nil

When a match exists, rassoc returns the whole row. When nothing matches, the method returns nil, which is easy to test with a guard clause. The search is short-circuiting and runs left to right, so if the same value appears in more than one pair, the one that comes first wins.

Practical Examples

Environment configuration

env_settings = [
  ["development", { host: "localhost", port: 3000 }],
  ["production",  { host: "example.com", port: 80 }],
  ["test",        { host: "127.0.0.1", port: 3001 }]
]

record = env_settings.rassoc({ host: "example.com", port: 80 })
record[0]  # => "production"

Looking up a record by its value column is a common use case. The result is the whole row, which means the caller can pick the key, the value, or both. The same shape fits any “find the row where column equals X” pattern.

Command and operator dispatch

operations = [
  ["+", :+],
  ["-", :-],
  ["*", :*],
  ["/", :/]
]

op = operations.rassoc(:*)
5.send(op[0], 3)  # => 15

Pairing a name with a callable is a compact way to build a dispatch table. The lookup finds the right entry, and the caller pulls out whichever column it needs. The same idea scales to command menus, status codes, and operator handlers.

Symbol and mixed-value tables

status_codes = [
  [200, :ok],
  [301, :moved],
  [404, :not_found],
  [500, :error]
]

status_codes.rassoc(:not_found)  # => [404, :not_found]

The method works with any value type that supports ==: integers, symbols, strings, hashes, even other nested pairs. The comparison is ==, not eql?, so 1 does not match 1.0, and :foo does not match "foo". That type strictness is usually what you want, but it can surprise you when the table mixes numeric types or symbol/string keys.

Behaviour Notes

Skipped elements. A scalar, string, or hash sitting alongside the rows is simply ignored — no error, no warning. This means rassoc quietly tolerates a slightly messy table, but it also means a typo that turns a row into a string will silently produce nil instead of raising.

The empty-row gotcha. A row shorter than two elements reports nil at index [1], so it will match a search for nil:

rows = [[:a, 1], [], [:b, 2]]
rows.rassoc(nil)  # => []

If your data can contain empty or single-element rows, guard against this or filter them out before calling rassoc(nil).

The result is a reference, not a copy. Mutating the returned row mutates the original:

table = [["a", 1], ["b", 2]]
row = table.rassoc(1)
row << 99
table  # => [["a", 1, 99], ["b", 2]]

If you need a detached copy, call dup (shallow) or deep_dup from ActiveSupport on the result.

Linear scan. rassoc walks the rows in order, so it is O(n). For small tables this is fine; for large ones, restructure the data into a Hash keyed by what you want to look up.

Return Value

[[:x, "hit"], [:y, "miss"]].rassoc("hit")   # => [:x, "hit"]
[[:x, "hit"], [:y, "miss"]].rassoc("nope")  # => nil

The return value is either the matching row (a reference into the original) or nil if no row matches. There is no block form and no bang variant — rassoc! does not exist.

Comparison with assoc

table = [[1, "one"], [2, "two"], [3, "three"]]

table.assoc(2)       # => [2, "two"]    # searches first column
table.rassoc("two")  # => [2, "two"]    # searches second column

assoc and rassoc are two halves of the same idea. Pick assoc when you know the key and want the row; pick rassoc when you know the value and want the row. Both return the same shape (a row or nil), and both skip non-row values. For a hash-based version of the same pattern, see Hash#rassoc.

See Also