Hash#delete
delete(key)
Removes the key-value pair for the given key from the hash and returns the associated value.
scores = { alice: 95, bob: 87, carol: 92 }
deleted_value = scores.delete(:bob)
# => 87
scores
# => { alice: 95, carol: 92 }
If key is not found, delete returns nil:
scores = { alice: 95, bob: 87 }
scores.delete(:unknown)
# => nil
With an ifnone block
Pass a block to delete and it will be called (with no arguments) when the key is not found. The block’s return value becomes the return value of delete instead of nil:
scores = { alice: 95, bob: 87 }
deleted = scores.delete(:unknown) { |k| "Key '#{k}' not found" }
# => "Key 'unknown' not found"
The block receives the key as an argument, so you can interpolate it into the error message:
h = { a: 1, b: 2 }
result = h.delete(:z) { |key| raise KeyError, "Missing key: #{key}" }
# => raises KeyError: "Missing key: z"
Common patterns
Rejecting nil values
delete is often used after fetching a value to ensure it’s not nil:
config = { debug: false, env: "production", port: nil }
port = config.delete(:port) # Returns nil, not 3000 as default
# => nil
Conditional removal with a guard
Use delete in a conditional when you only want to remove an entry if it matches a condition:
users = { alice: "admin", bob: "editor", carol: "viewer" }
if users[:bob] == "editor"
users.delete(:bob)
end
# => "editor"
users
# => { alice: "admin", carol: "viewer" }
Destructuring with slice
To atomically extract a subset of keys and remove them from the hash:
data = { name: "Alice", age: 30, city: "London", email: "alice@example.com" }
extracted = data.slice!(:name, :email)
# => { name: "Alice", email: "alice@example.com" }
data
# => { age: 30, city: "London" }
Note: slice! is more idiomatic for extracting multiple keys at once.
Edge cases
-
Deleting from a frozen hash raises
FrozenError:h = { a: 1 }.freeze h.delete(:a) # => FrozenError (can't modify frozen Hash) -
Deleting a key that doesn’t exist returns
nil(or the block result if a block was given):{}.delete(:missing) # => nil -
The returned value is the original value before deletion, not the key:
h = { key: { nested: "value" } } deleted = h.delete(:key) deleted[:nested] = "modified" # This mutates the deleted object # => { nested: "modified" }
Performance
Hash#delete is an O(1) operation on average for hash buckets, but in the worst case (hash collisions) it can degrade to O(n) where n is the number of entries. In practice, Ruby’s hash implementation is highly optimized and deletion is very fast.
See Also
- Hash#reject — returns a new hash with entries removed (non-mutating)
- Hash#slice — extract a subset of keys without mutating the original
- Hash#except — remove specific keys, returning a new hash