Array#assoc
array.assoc(key) -> sub_array or nil The assoc method searches an array of arrays (like a table) for the first sub-array whose first element equals the search key. It’s perfect for looking up data in simple key-value tables.
Basic Usage
# Simple lookup
table = [["a", 1], ["b", 2], ["c", 3]]
table.assoc("b") # => ["b", 2]
table.assoc("x") # => nil
When the key exists in the first column of any sub-array, assoc returns the entire matching row. When the key is absent, the method returns nil, which makes the result easy to test with a simple conditional. The search stops at the first match, so the order of the sub-arrays determines which row is returned when duplicates exist.
Practical Examples
Configuration Tables
# Environment config lookup
env_config = [
["development", { host: "localhost", port: 3000 }],
["production", { host: "example.com", port: 80 }],
["test", { host: "127.0.0.1", port: 3001 }]
]
env_config.assoc("production")
# => ["production", {:host=>"example.com", :port=>80}]
Looking up configuration values by environment name is a natural fit for assoc. The first element is the environment key, and the second element carries whatever settings that environment needs. Picking a different environment is just a matter of changing the lookup key, which keeps the configuration code short and declarative.
Menu/command lookup
commands = [
["new", CreateProjectCommand],
["open", OpenProjectCommand],
["save", SaveCommand],
["exit", ExitCommand]
]
cmd = commands.assoc("save")
cmd[1].new.execute if cmd
This pattern works well for command dispatch tables where each entry pairs a name with a class or callable. The lookup returns the matching pair, and the second element can be instantiated or invoked as needed. Checking for nil before using the result prevents errors when the command name is not recognised.
CSV-like data
# Like a simple database
users = [
["alice", "Alice Anderson", "alice@example.com"],
["bob", "Bob Builder", "bob@example.com"],
["carol", "Carol Clark", "carol@example.com"]
]
users.assoc("bob") # => ["bob", "Bob Builder", "bob@example.com"]
Treating an array of arrays as a simple database is a lightweight pattern that works well when the data is small and read-heavy. Each row has a predictable structure, and assoc finds the row by its first field. For larger datasets or frequent lookups, a hash would perform better, but for quick scripts and small tables the array-based approach keeps things simple.
Method Dispatch
operations = [
["+", :+],
["-", :-],
["*", :*],
["/", :/]
]
op = operations.assoc("*")
5.send(op[1], 3) # => 15
Using assoc to map operator symbols to their method names is a compact way to build a calculator or expression evaluator. The lookup finds the matching operator, and send dynamically calls the corresponding method on the receiver. This keeps the dispatch logic in a single table rather than spread across a long case statement.
With different key types
# Integer keys
scores = [[1, 100], [2, 95], [3, 87]]
scores.assoc(2) # => [2, 95]
# Symbol keys
mapping = [[:red, "#f00"], [:green, "#0f0"], [:blue, "#00f"]]
mapping.assoc(:green) # => [:green, "#0f0"]
assoc works with any key type that supports == comparison, including integers, symbols, and strings. The lookup is type-sensitive, so assoc(2) will not match a string key "2". Keeping the key types consistent across the table avoids subtle mismatches where a lookup silently returns nil because the types do not line up. When the data structure uses homogeneous keys, the method behaves predictably and the calling code stays simple. For heterogeneous key scenarios, a quick type check before the lookup can prevent confusing results.
Return Value
# Returns the entire sub-array
result = [["a", 1], ["b", 2]].assoc("a")
puts result.inspect # => ["a", 1]
# Returns nil if not found
result = [["a", 1]].assoc("z")
puts result # => nil
Use assoc for simple table lookups
assoc works well when the array already behaves like a small table of pairs. The first element of each sub-array acts like the key, and the method returns the first match it finds. That makes the call easy to read in places where you need a quick lookup without building a hash first. It is a good fit for small, ordered data sets where the shape of the array is already meaningful and the lookup rules are straightforward.
Keep the structure predictable
The method expects each item to be an array with a first element that can be compared against the search key. That predictability is what makes the method useful, but it also means the structure has to stay consistent. If the array mixes shapes, the lookup becomes harder to trust. In practice, assoc shines when the caller controls the data format and wants a lightweight way to search it without changing it into a different container.
Match it to the right data shape
assoc is not trying to replace Hash; it is there for the cases where the data already arrives as an array of pairs or small records. That can happen with command tables, CSV-style rows, or lookup lists built from external input. If the values get larger or the lookup becomes frequent, a hash may be the better fit. But when the table is tiny and the sequence matters, assoc keeps the code short and direct.
Comparison with rassoc
# assoc searches first column
table = [[1, "one"], [2, "two"], [3, "three"]]
table.assoc(2) # => [2, "two"]
# rassoc searches second column
table.rassoc("two") # => [2, "two"]