5. Hashes

Introduction


age = {
    "Nat"  , 24,
    "Jules", 25,
    "Josh" , 17,
}
age{"Nat"}   = 24
age{"Jules"} = 25
age{"Josh"}  = 17

Adding an Element to a Hash

food_color = {
    "Apple" , "red",
    "Banana", "yellow",
    "Lemon" , "yellow",
    "Carrot", "orange",
}
food_color{"Raspberry"} = "pink"
println("Known foods:")
food_color.keys.each(println)

Testing for the Presence of a Key in a Hash

("Banana", "Martini").each(name ->
    println("{name} is a {if food_color.key?(name) then "food" else "drink"}")
)
# Banana is a food.
# Martini is a drink.

Deleting from a Hash

food_color.remove_key!("Banana")

Traversing a Hash

food_color.each(food, color -> "{food} is {color}.".println)
food_color.keys.sort.each(food -> "{food} is {food_color{food}}.".println)

Printing a Hash

hash.each(k,v -> "{k} => {v}".println)

Retrieving from a Hash in Insertion Order

# the default should be to keep the order, so no pb here.

Hashes with Multiple Values Per Key

ttys = {}
popen("who").each(s ->
    user, tty = s.words[0,1]
    #ttys{user} = [] if not ttys.key?(user)    <- not needed, auto created with ***
    ttys{user}.push!(tty)
)
ttys.keys.sort.each(user -> "{user}: {ttys{user}.join(", ")}".println)

# or the more functional:
popen("who").foldl({}, (ttys, s ->
    user, tty = s.words[0,1]
    #ttys{user} = [] if not ttys.key?(user)    <- not needed, auto created with ***
    ttys{user}.push(tty)
)).keys.sort.each(user -> "{user}: {ttys{user}.join(", ")}".println)

Inverting a Hash

surname = { "Mickey","Mantle" , "Babe","Ruth" }
println(surname.value2key("Mantle"))    # => Mickey

Sorting a Hash

food_color.keys.sort.each(food -> "{food} is {food_color{food}}.".println)

Merging Hashes

merged = a + b

drink_color = { "Galliano","yellow" , "Mai Tai","blue" }
ingested_colors = drink_color + food_color

substance_color = drink_color + food_color
intersection(drink_color, food_color).each(k,_ ->
    println("Warning: {k} seen twice. Using the last definition.")
)

Finding Common or Different Keys in Two Hashes

all_colors += new_colors

common = intersection(hash1, hash2).keys
common = intersection(hash1.keys, hash2.keys)

citrus_color = {
    "Lemon", "yellow",
    "Orange", "orange",
    "Lime", "green",
}
non_citrus = difference(food_color, citrus_color).keys
non_citrus = difference(food_color.keys, citrus_color.keys)

Hashing References

# no pb, merd's dicts handle any kind of objects which have Eq

Presizing a Hash

# TODO

Finding the Most Common Anything

count = {}
array.each(e -> count{e}++)

Representing Relationships Between Data

father = {
    "Cain"      , "Adam",
    "Abel"      , "Adam",
    "Seth"      , "Adam",
    "Enoch"     , "Cain",
    "Irad"      , "Enoch",
    "Mehujael"  , "Irad",
    "Methusael" , "Mehujael",
    "Lamech"    , "Methusael",
    "Jabal"     , "Lamech",
    "Jubal"     , "Lamech",
    "Tubalcain" , "Lamech",
    "Enos"      , "Seth",
}
Sys::stdall.each(e ->
    e.chomp!
    
    #fathers = e : e.unfoldr1(e -> Some(father{e}) or None)
    #println(fathers.join(" "))

    print("{e}")
    try loop
        e = fathers{e}
        print("{e} ")
    with _ -> println("")
)

Sys::stdall.each(e ->
    e.chomp!
    children = father.key2values(e) ||| [ "nobody" ]
    println("{e} begat {children.join(", ")}.")
)

includes = {}
files.each(file ->
    try
        file.open.each(s ->
            s.pattern_matches(
                "^\s*#\s+include\s+<(.*?)>",
                f -> includes.push!(f)
            )
        )
    with File_error(err) -> warn("Couldn't read {file}: {err}; skipping.\n")
)
include_free =
    # list of files that don't include others
    difference(includes.values.flatten.uniq, includes.keys)

Program: dutree