rubyguides

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