NAME
Sidef::Types::Hash::Hash - Associative hash table mapping keys to values with convenient collection methods.
DESCRIPTION
This class implements a hash (associative array) data type, providing key-value storage and various methods for hash manipulation, iteration, transformation, and set operations.
A Hash is an unordered collection of key-value pairs where each unique key maps to exactly one value. Keys are compared using structural equality.
SYNOPSIS
# Creating hashes
var hash = Hash(a => 1, b => 2, c => 3)
var h = Hash(:foo, :bar) # Keys with nil values
# Accessing values
say hash{:a} #=> 1
say hash.item(:b) #=> 2
# Setting values
hash{:d} = 4
hash.append(e => 5, f => 6)
# Basic operations
say hash.keys #=> [:a, :b, :c, :d, :e, :f]
say hash.values #=> [1, 2, 3, 4, 5, 6]
say hash.len #=> 6
say hash.has(:a) #=> true
# Iteration
hash.each { |key, value|
say "#{key} => #{value}"
}
# Transformation
var doubled = hash.map_v { _1 * 2 }
var filtered = hash.grep { |k, v| v > 2 }
# Set operations
var h1 = Hash(a => 1, b => 2)
var h2 = Hash(b => 3, c => 4)
say (h1 | h2) #=> Hash(a => 1, b => 2, c => 4) # Union
say (h1 & h2) #=> Hash(b => 2) # Intersection
say (h1 - h2) #=> Hash(a => 1) # Difference
say (h1 ^ h2) #=> Hash(a => 1, c => 4) # Symmetric difference
INHERITS
Inherits methods from Sidef::Object::Object.
CONSTRUCTION
new
Hash.new
Hash.new(pairs...)
Creates and returns a new Hash object, optionally initialized with the given key-value pairs.
var h1 = Hash.new
var h2 = Hash.new(a => 1, b => 2)
var h3 = Hash(a => 1, b => 2) # Shorthand
Aliases: call
ACCESSING VALUES
item
hash.item(key)
Returns the value associated with the given key, or nil if the key does not exist.
var h = Hash(a => 1, b => 2)
say h.item(:a) #=> 1
say h.item(:z) #=> nil
This is equivalent to subscript notation: hash{key}.
items
hash.items(keys...)
Returns an Array of values for the specified keys. Returns nil for keys that do not exist.
var h = Hash(a => 1, b => 2, c => 3)
say h.items(:a, :c, :z) #=> [1, 3, nil]
fetch
hash.fetch(key, default)
Returns the value for the given key if it exists; otherwise returns the default value.
var h = Hash(a => 1, b => 2)
say h.fetch(:a, 0) #=> 1
say h.fetch(:z, 0) #=> 0
say h.fetch(:z, nil) #=> nil
Unlike direct subscript access (hash{key}), fetch allows you to distinguish between a missing key and a key whose value is nil.
dig
hash.dig(key, keys...)
Recursively retrieves a nested value by traversing a chain of keys. Returns the value at the nested key path, or nil if any key in the path does not exist.
var h = Hash(
a => Hash(
b => Hash(
c => 42
)
)
)
say h.dig(:a, :b, :c) #=> 42
say h.dig(:a, :x) #=> nil
This is safer than chaining subscript operations when intermediate keys may be absent.
TESTING AND COUNTING
has
hash.has(key)
Returns true if the given key exists in the hash, false otherwise.
var h = Hash(a => 1, b => nil)
say h.has(:a) #=> true
say h.has(:b) #=> true (key exists even with nil value)
say h.has(:z) #=> false
Aliases: exists, has_key, haskey, contain, contains, include, includes
is_empty
hash.is_empty
Returns true if the hash contains no key-value pairs, false otherwise.
var h1 = Hash()
var h2 = Hash(a => 1)
say h1.is_empty #=> true
say h2.is_empty #=> false
same_keys
hash.same_keys(other)
Returns true if the hash has exactly the same set of keys as other (another hash), false otherwise. Values are not compared.
var h1 = Hash(a => 1, b => 2)
var h2 = Hash(a => 10, b => 20)
var h3 = Hash(a => 1, c => 3)
say h1.same_keys(h2) #=> true
say h1.same_keys(h3) #=> false
len
hash.len
Returns the number of key-value pairs in the hash.
var h = Hash(a => 1, b => 2, c => 3)
say h.len #=> 3
Aliases: size, length
count
hash.count(key)
hash.count { |key, value| ... }
When called with a key, returns 1 if the key exists in the hash, 0 otherwise.
When called with a block, returns the number of key-value pairs for which the block returns true.
var h = Hash(a => 1, b => 2, c => 3, d => 4)
say h.count(:b) #=> 1
say h.count(:z) #=> 0
say h.count { |k, v| v > 2 } #=> 2
count_by
hash.count_by { |key, value| ... }
Returns the number of key-value pairs for which the block returns a true value. The block receives (key, value) as arguments.
var h = Hash(a => 1, b => 2, c => 3, d => 4)
say h.count_by { |k, v| v.is_even } #=> 2
KEYS, VALUES, AND PAIRS
keys
hash.keys
Returns an Array containing all keys in the hash.
var h = Hash(a => 1, b => 2, c => 3)
say h.keys #=> [:a, :b, :c]
Note: Hash keys are unordered, so the order of keys in the returned array is not guaranteed.
values
hash.values
Returns an Array containing all values in the hash.
var h = Hash(a => 1, b => 2, c => 3)
say h.values #=> [1, 2, 3]
Note: Since hash keys are unordered, the order of values in the returned array is not guaranteed.
kv
hash.kv
Returns an Array of Pair objects, where each Pair contains a key and its associated value.
var h = Hash(a => 1, b => 2)
say h.kv #=> [Pair(:a, 1), Pair(:b, 2)]
# Useful for iteration with destructuring
h.kv.each { |pair|
say "#{pair.key} => #{pair.value}"
}
Aliases: to_a, pairs, to_array
get_pair
hash.get_pair(key)
Returns a Pair object containing the given key and its associated value.
var h = Hash(a => 1, b => 2)
var p = h.get_pair(:a)
say p #=> Pair(:a, 1)
say p.key #=> :a
say p.value #=> 1
Returns a Pair with a nil value if the key does not exist.
get_pairs
hash.get_pairs(keys...)
Returns an Array of Pair objects for the specified keys.
var h = Hash(a => 1, b => 2, c => 3)
var pairs = h.get_pairs(:a, :c)
say pairs #=> [Pair(:a, 1), Pair(:c, 3)]
Missing keys produce Pair objects with nil values.
slice
hash.slice(keys...)
Returns a new hash containing only the specified keys. Keys that exist in the original hash keep their values, and keys that do not exist are included in the result with nil values.
var h = Hash(a => 1, b => 2, c => 3, d => 4)
var subset = h.slice(:a, :c, :z)
say subset #=> Hash(a => 1, c => 3, z => nil)
Note: Missing keys are included with nil values. See lsel for the Array/to_list variant of this operation.
lsel
hash.lsel(keys_array)
Performs a linear selection: returns a new hash containing the keys specified in keys_array, including missing keys with nil values. The main difference from slice is the argument shape: lsel takes an Array (or any object responding to to_list), while slice takes variadic keys.
var h = Hash(a => 1, b => 2)
var selected = h.lsel([:a, :c])
say selected #=> Hash(a => 1, c => nil)
The argument must be an Array (or any object responding to to_list).
Aliases: linsel, linear_selection
MODIFYING THE HASH
append
hash.append(pairs...)
Appends the given key-value pairs to the hash in-place and returns the modified hash. If a key already exists, its value is updated.
var h = Hash(a => 1)
h.append(b => 2, c => 3)
say h #=> Hash(a => 1, b => 2, c => 3)
clear
hash.clear
Removes all key-value pairs from the hash in-place and returns the now-empty hash.
var h = Hash(a => 1, b => 2)
h.clear
say h #=> Hash()
say h.len #=> 0
delete
hash.delete(keys...)
Removes the specified keys from the hash in-place and returns the deleted values as an Array (or a single value if only one key was given).
var h = Hash(a => 1, b => 2, c => 3)
say h.delete(:b) #=> 2
say h.delete(:a, :c) #=> [1, 3]
say h #=> Hash()
Aliases: remove
delete_if
hash.delete_if { |key, value| ... }
Deletes all key-value pairs for which the block returns true. The block receives (key, value) as arguments. Returns the modified hash.
var h = Hash(a => 1, b => 2, c => 3, d => 4)
h.delete_if { |k, v| v.is_even }
say h #=> Hash(a => 1, c => 3)
This is the in-place counterpart to grep, which returns a new filtered hash instead of modifying the original.
set_keys
hash.set_keys(keys...)
Sets the specified keys to nil in the hash in-place and returns the modified hash.
var h = Hash(a => 1)
h.set_keys(:b, :c)
say h #=> Hash(a => 1, b => nil, c => nil)
This is useful for pre-initializing keys before assigning their actual values.
merge_values
hash.merge_values(other_hash)
Updates the values in the hash for keys that also exist in other_hash. Only keys already present in the original hash are affected; no new keys are added. Modifies the hash in-place and returns it.
var h1 = Hash(a => 1, b => 2, c => 3)
var h2 = Hash(b => 20, c => 30, d => 40)
h1.merge_values(h2)
say h1 #=> Hash(a => 1, b => 20, c => 30)
Note: Key :d from h2 was not added because it did not already exist in h1.
ITERATION
each
hash.each { |key, value| ... }
hash.each
Iterates over each key-value pair in the hash, calling the block with (key, value). When called without a block, acts as a stateful iterator, returning one key-value pair per call (or nil when the iteration is exhausted).
var h = Hash(a => 1, b => 2, c => 3)
h.each { |k, v|
say "#{k} => #{v}"
}
# Stateful iterator usage
loop {
var (k, v) = h.each \\ break
say "#{k} => #{v}"
}
Aliases: each_kv, each_pair
each_k
hash.each_k { |key| ... }
Iterates over each key in the hash, calling the block with the key. Returns the hash.
var h = Hash(a => 1, b => 2, c => 3)
h.each_k { |k|
say k
}
Aliases: each_key
each_v
hash.each_v { |value| ... }
Iterates over each value in the hash, calling the block with the value. Returns the hash.
var h = Hash(a => 1, b => 2, c => 3)
h.each_v { |v|
say v * 2
}
Aliases: each_value
TRANSFORMATION AND FILTERING
map
hash.map { |key, value| ... }
Transforms the hash by applying the block to each key-value pair. The block receives (key, value) and should return a new key-value pair as a flat two-element list. Returns a new hash built from the collected pairs.
var h = Hash(a => 1, b => 2)
var mapped = h.map { |k, v|
(k.uc, v * 10)
}
say mapped #=> Hash(A => 10, B => 20)
Aliases: map_kv
map_v
hash.map_v { |key, value| ... }
Returns a new hash with the same keys but with values transformed by the block. The block receives (key, value) and should return the new value.
var h = Hash(a => 1, b => 2, c => 3)
var doubled = h.map_v { |k, v| v * 2 }
say doubled #=> Hash(a => 2, b => 4, c => 6)
# The block may also take just the value
var squared = h.map_v { _1 ** 2 }
say squared #=> Hash(a => 1, b => 4, c => 9)
Aliases: map_val
grep
hash.grep { |key, value| ... }
Returns a new hash containing only the key-value pairs for which the block returns true. The block receives (key, value) as arguments.
var h = Hash(a => 1, b => 2, c => 3, d => 4)
var evens = h.grep { |k, v| v.is_even }
say evens #=> Hash(b => 2, d => 4)
This is the non-destructive counterpart to delete_if.
Aliases: grep_kv, select
grep_v
hash.grep_v { |value| ... }
Returns a new hash containing only the key-value pairs for which the block (called with the value only) returns true.
var h = Hash(a => 1, b => 2, c => 3, d => 4)
var evens = h.grep_v { .is_even }
say evens #=> Hash(b => 2, d => 4)
Aliases: grep_val
collect
hash.collect { |key, value| ... }
Iterates over each key-value pair, calling the block with (key, value), and collects all return values into a new Array.
var h = Hash(a => 1, b => 2, c => 3)
var result = h.collect { |k, v|
"#{k}=#{v}"
}
say result #=> ["a=1", "b=2", "c=3"]
Aliases: collect_kv
flip
hash.flip
Returns a new hash with keys and values swapped. The original values become the new keys, and the original keys become the new values.
var h = Hash(a => 1, b => 2, c => 3)
say h.flip #=> Hash(1 => :a, 2 => :b, 3 => :c)
Note: If multiple keys share the same value, only one key-value pair will survive in the flipped hash (the last one encountered wins).
Aliases: invert, reverse
SORTING
sort
hash.sort
hash.sort { |a, b| ... }
Returns an Array of Pairs sorted by key. When no block is given, keys are sorted in lexicographic order. When a block is provided, it is used as a comparator for the keys.
var h = Hash(c => 3, a => 1, b => 2)
say h.sort #=> [Pair(:a, 1), Pair(:b, 2), Pair(:c, 3)]
# Custom comparator (reverse order)
var rev = h.sort { |a, b| b <=> a }
say rev #=> [Pair(:c, 3), Pair(:b, 2), Pair(:a, 1)]
sort_by
hash.sort_by { |key, value| ... }
Returns an Array of Pairs sorted by the values returned by the block. The block receives (key, value) as arguments.
var h = Hash(a => 3, b => 1, c => 2)
var sorted = h.sort_by { |k, v| v }
say sorted #=> [Pair(:b, 1), Pair(:c, 2), Pair(:a, 3)]
# Sort by key length
var by_len = h.sort_by { |k, v| k.len }
min_by
hash.min_by { |key, value| ... }
Returns the key-value Pair for which the block returns the minimum value. The block receives (key, value) as arguments.
var h = Hash(a => 3, b => 1, c => 5, d => 2)
var min_pair = h.min_by { |k, v| v }
say min_pair #=> Pair(:b, 1)
max_by
hash.max_by { |key, value| ... }
Returns the key-value Pair for which the block returns the maximum value. The block receives (key, value) as arguments.
var h = Hash(a => 3, b => 1, c => 5, d => 2)
var max_pair = h.max_by { |k, v| v }
say max_pair #=> Pair(:c, 5)
OPERATORS
==
hash1 == hash2
Returns true if both hashes have the same keys with equal values (structural equality).
var h1 = Hash(a => 1, b => 2)
var h2 = Hash(b => 2, a => 1)
say (h1 == h2) #=> true
Aliases: eq
≠
hash1 ≠ hash2
Returns true if the two hashes are not structurally equal (different keys or different values).
var h1 = Hash(a => 1)
var h2 = Hash(a => 2)
say (h1 ≠ h2) #=> true
Aliases: !=, ne
+
hash1 + hash2
Returns a new hash containing all key-value pairs from both hashes. If a key exists in both, the value from the second hash takes precedence (right-hand side wins).
var h1 = Hash(a => 1, b => 2)
var h2 = Hash(b => 20, c => 30)
say (h1 + h2) #=> Hash(a => 1, b => 20, c => 30)
Aliases: merge, concat
-
hash1 - hash2
Returns the set difference of two hashes. The result contains only keys that exist in the first hash but not in the second.
var h1 = Hash(a => 1, b => 2, c => 3)
var h2 = Hash(b => 20, d => 40)
say (h1 - h2) #=> Hash(a => 1, c => 3)
Aliases: sub, diff, difference
&
hash1 & hash2
Returns the intersection of two hashes. The result contains only keys that exist in both hashes, with values taken from the first hash.
var h1 = Hash(a => 1, b => 2, c => 3)
var h2 = Hash(b => 20, c => 30, d => 40)
say (h1 & h2) #=> Hash(b => 2, c => 3)
Aliases: and, intersection
|
hash1 | hash2
Returns the union of two hashes. The result contains all keys from both hashes; for keys present in both, the value from the first hash takes precedence (left-hand side wins).
var h1 = Hash(a => 1, b => 2)
var h2 = Hash(b => 20, c => 30)
say (h1 | h2) #=> Hash(a => 1, b => 2, c => 30)
Note the difference from + (merge): union keeps the left-hand value for common keys, while merge keeps the right-hand value.
Aliases: or, union
^
hash1 ^ hash2
Returns the symmetric difference of two hashes. The result contains keys that exist in either hash but not in both.
var h1 = Hash(a => 1, b => 2)
var h2 = Hash(b => 20, c => 30)
say (h1 ^ h2) #=> Hash(a => 1, c => 30)
Aliases: xor, symdiff, symmetric_difference
...
hash...
Returns the hash as a flat list of alternating keys and values. This is useful for unpacking a hash into an argument list or for converting it to other data structures.
var h = Hash(a => 1, b => 2)
say h... #=> [:a, 1, :b, 2]
Aliases: to_list
CONVERSION
dump
hash.dump
Returns a string representation of the hash.
var h = Hash(a => 1, b => 2)
say h.dump #=> "Hash(a => 1, b => 2)"
Aliases: to_s, to_str
to_set
hash.to_set
Converts the hash's keys to a Set object. The hash values are ignored.
var h = Hash(a => 1, b => 2, c => 3)
var set = h.to_set
say set #=> Set(:a, :b, :c)
to_bag
hash.to_bag
Converts the hash's keys to a Bag object. The hash values are ignored.
var h = Hash(a => 1, b => 2, c => 3)
var bag = h.to_bag
say bag #=> Bag(:a, :b, :c)
as_tree
hash.as_tree(root)
Returns the hash as a tree structure represented as nested Pairs, using the given root as the tree's root label. Nested hashes are recursively converted to sub-trees. Non-hash leaf values are represented as Pairs with an empty array []; only the key hierarchy is preserved, not the leaf values themselves.
var h = Hash(
a => Hash(b => 1),
c => 2
)
say h.as_tree(:root)
#=> Pair(:root, [Pair(:a, [Pair(:b, [])]), Pair(:c, [])])
This is useful for visualizing or processing hashes as hierarchical data structures.
EXAMPLES
Frequency Counting
var text = "hello world"
var freq = Hash()
text.each_char { |char|
freq{char} := 0
freq{char}++
}
say freq #=> Hash(h => 1, e => 1, l => 3, ...)
Grouping Data
var people = [
Hash(name => "Alice", age => 30),
Hash(name => "Bob", age => 25),
Hash(name => "Carol", age => 30)
]
var by_age = Hash()
people.each { |person|
var age = person{:age}
by_age{age} := []
by_age{age} << person
}
Transforming Data
var prices = Hash(apple => 1.50, banana => 0.75, orange => 2.00)
# Apply a discount
var discounted = prices.map_v { _1 * 0.9 }
# Filter expensive items
var expensive = prices.grep { |k, v| v > 1.00 }
Merging with Custom Logic
var defaults = Hash(color => :red, size => :medium, count => 1)
var options = Hash(size => :large)
# Keep defaults for missing keys
var config = defaults + options
say config #=> Hash(color => :red, size => :large, count => 1)
SEE ALSO
Sidef::Types::Array::Array, Sidef::Types::Set::Set, Sidef::Types::Bag::Bag