← Code Compare

Hash Maps

A hash map (also called a dictionary or associative array) stores key/value pairs and offers fast insert, look-up, and iteration. The three core operations shown here are inserting a pair, looking a key up safely (handling the absent case), and iterating over every entry.

Show: GujiGoOCamlHaskellPerlRakuRustPython
Guji
sub main() {
    %ages = {"ada": 36, "alan": 41}
    %all = %ages.set("grace", 45)

    match %all.get("ada") {
        Some($a) { print("ada is $a") }
        None     { print("ada is unknown") }
    }
    $has = %all.has_key("alan")
    print("has alan: $has")

    for $name, $age in %all {
        print("$name -> $age")
    }
    $n = %all.keys().count()
    print("count: $n")
}

A map binding carries the % sigil and is indexed with braces: %all{"ada"}. Because bindings are immutable by default, set returns a fresh map rather than mutating in place, so the result is bound to a new name. get returns Option[V], forcing the absent case to be handled with match, and a map for loop binds two variables, key then value.

Go
package main

import (
	"fmt"
	"sort"
)

func main() {
	ages := map[string]int{"ada": 36, "alan": 41}
	ages["grace"] = 45 // insert

	if a, ok := ages["ada"]; ok { // look up
		fmt.Println("ada is", a)
	}
	_, has := ages["alan"]
	fmt.Println("has alan:", has)

	keys := make([]string, 0, len(ages))
	for k := range ages {
		keys = append(keys, k)
	}
	sort.Strings(keys)
	for _, name := range keys { // iterate
		fmt.Printf("%s -> %d\n", name, ages[name])
	}
	fmt.Println("count:", len(ages))
}

Go's built-in map[K]V is created with a literal and assigned to directly. The two-value index form a, ok := ages["ada"] distinguishes a present key from a missing one, since a bare read returns the zero value. Iteration order over a map is deliberately randomized, so the keys are collected and sorted first for stable output.

OCaml
let () =
  let ages = Hashtbl.create 16 in
  Hashtbl.replace ages "ada" 36;
  Hashtbl.replace ages "alan" 41;
  Hashtbl.replace ages "grace" 45;  (* insert *)

  (match Hashtbl.find_opt ages "ada" with   (* look up *)
   | Some a -> Printf.printf "ada is %d\n" a
   | None -> print_endline "ada is unknown");
  Printf.printf "has alan: %b\n" (Hashtbl.mem ages "alan");

  let pairs = Hashtbl.fold (fun k v acc -> (k, v) :: acc) ages [] in
  List.iter (fun (k, v) -> Printf.printf "%s -> %d\n" k v)
    (List.sort compare pairs);   (* iterate *)
  Printf.printf "count: %d\n" (Hashtbl.length ages)

The standard Hashtbl module provides a mutable hash table; replace inserts or overwrites a binding. find_opt returns 'a option, so the missing case is handled explicitly with a match rather than raising Not_found. Hashtbl.fold collects every pair into a list, which is sorted for deterministic iteration.

Haskell
import qualified Data.Map as Map
import Data.Map (Map)

main :: IO ()
main = do
  let ages0 = Map.fromList [("ada", 36), ("alan", 41)] :: Map String Int
      ages  = Map.insert "grace" 45 ages0  -- insert

  case Map.lookup "ada" ages of            -- look up
    Just a  -> putStrLn ("ada is " ++ show a)
    Nothing -> putStrLn "ada is unknown"
  putStrLn ("has alan: " ++ show (Map.member "alan" ages))

  mapM_ (\(k, v) -> putStrLn (k ++ " -> " ++ show v))
        (Map.toList ages)                  -- iterate, key-ordered
  putStrLn ("count: " ++ show (Map.size ages))

Data.Map is an immutable, balanced-tree map, so insert returns a new map sharing structure with the old one rather than mutating. lookup returns Maybe v, and the Just/Nothing cases are matched directly. Map.toList yields the pairs already sorted by key, which suits the lazy, pure style.

Perl
use strict;
use warnings;

my %ages = (ada => 36, alan => 41);
$ages{grace} = 45;  # insert

print "ada is ", ($ages{ada} // "unknown"), "\n";  # look up
print "has alan: ", (exists $ages{alan} ? "true" : "false"), "\n";

for my $name (sort keys %ages) {  # iterate
    print "$name -> $ages{$name}\n";
}
print "count: ", scalar(keys %ages), "\n";

A %hash is Perl's native associative array; a single element is reached with the $ages{key} scalar form. The defined-or operator // supplies a default for an absent key, while exists tests membership without autovivifying. keys is sorted so iteration order is stable.

Raku
my %ages = ada => 36, alan => 41;
%ages<grace> = 45;  # insert

say "ada is ", %ages<ada> // "unknown";  # look up
say "has alan: ", %ages<alan>:exists;

for %ages.keys.sort -> $name {  # iterate
    say "$name -> %ages{$name}";
}
say "count: ", %ages.elems;

Raku hashes use the % sigil and the angle-bracket %ages<key> shortcut for string subscripts. The :exists adverb tests for a key, and // provides a default when a value is missing. .keys, .sort, and .elems are methods on the hash, and string interpolation reaches an element inline with %ages{$name}.

Rust
use std::collections::HashMap;

fn main() {
    let mut ages: HashMap<&str, i32> = HashMap::new();
    ages.insert("ada", 36);
    ages.insert("alan", 41);
    ages.insert("grace", 45); // insert

    match ages.get("ada") {   // look up
        Some(a) => println!("ada is {a}"),
        None => println!("ada is unknown"),
    }
    println!("has alan: {}", ages.contains_key("alan"));

    let mut pairs: Vec<_> = ages.iter().collect();
    pairs.sort_by_key(|&(k, _)| *k);
    for (name, age) in pairs { // iterate
        println!("{name} -> {age}");
    }
    println!("count: {}", ages.len());
}

std::collections::HashMap needs a mut binding because insert mutates in place. get returns Option<&V>, so the missing case is handled with match rather than a panic, and contains_key tests membership. Iteration order is unspecified, so the pairs are collected into a Vec and sorted by key before printing.

Python
ages = {"ada": 36, "alan": 41}
ages["grace"] = 45  # insert

print("ada is", ages.get("ada", "unknown"))  # look up
print("has alan:", "alan" in ages)

for name, age in ages.items():  # iterate
    print(f"{name} -> {age}")
print("count:", len(ages))

The built-in dict is Python's hash map; a key is set with ages[key] = value. .get(key, default) looks a key up without raising KeyError, and the in operator tests membership. .items() yields key/value pairs for iteration, and since Python 3.7 a dict preserves insertion order.